C++代码调用C以及extern “C”用法

1 Gcc编译库测试

1.1 头文件(tool.h)

#ifndef __TOOL_H
#define __TOOL_H

#ifdef __cplusplus
extern “C” {
#endif

void hello();

#ifdef __cplusplus
}
#endif
#endif

1.2 source代码(tool.c)

#include “tool.h”
#include “stdio.h”
void hello(int val,const char* msg)
{
printf(“val=%d,msg=%s\n”,val,msg);
}

1.3 Gcc编译成静态库

gcc -c tool.c
ar -rcs libtool.a tool.o

1.4 查看符号信息

readelf -s -W libtool.a

File: libtool.a(tool.o)

Symbol table ‘.symtab’ contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tool.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 8
8: 0000000000000000 0 SECTION LOCAL DEFAULT 6
9: 0000000000000000 41 FUNC GLOBAL DEFAULT 1 hello
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf

1.5 测试代码

extern void hello(int val,const char* msg);
int main()
{
hello(1,“hello world”);
return 0;
}

1.6 编译测试代码

1.6.1 Gcc编译

gcc -o testc test.c -ltool
readelf -s -W testc | grep hello
53: 0000000000400547 41 FUNC GLOBAL DEFAULT 13 hello

1.6.2 g++编译

g++ -o testcpp test.c –ltool
编译报错
/tmp/ccP178In.o: In function main': test.c:(.text+0xf): undefined reference tohello(int, char const*)’
collect2: error: ld returned 1 exit status

此时,把测试代码中
extern void hello(int val,const char* msg);
修改为
extern “C” {void hello(int val,const char* msg);}
即能编译通过,即搜索hello函数时按C编译风格进行搜索函数符号信息,即hello。

2 G++编译库测试

2.1 G++编译成静态库

使用上面相同的c代码tool.c,编译生成静态库
g++ -c tool.c
ar -rcs libtool.a tool.o

2.2 查看符号信息

readelf -s -W libtool.a

File: libtool.a(tool.o)

Symbol table ‘.symtab’ contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tool.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 8
8: 0000000000000000 0 SECTION LOCAL DEFAULT 6
9: 0000000000000000 41 FUNC GLOBAL DEFAULT 1 _Z5helloiPKc
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf

2.3 编译测试代码

2.3.1 Gcc编译

测试代码
extern void hello(int val,const char* msg);
int main()
{
hello(1,“hello world”);
return 0;
}

gcc -o testc test.c –ltool
编译报错
/tmp/ccxA3ouR.o: In function main': test.c:(.text+0xf): undefined reference tohello’
collect2: error: ld returned 1 exit status
在链接过程出错,找不到符号信息hello,因为libtool.a中函数符号名称是_Z5helloiPKc,而链接的时候在按C方式搜索hello

2.3.2 g++编译

测试代码
extern void hello(int val,const char* msg);
int main()
{
hello(1,“hello world”);
return 0;
}

g++ -o testcpp test.c –ltool
g++: error: –ltool: No such file or directory
这里把lib库放前面,或则使用静态库的全名,或则目标文件:
g++ test.c -ltool -o testcpp
g++ -o testcpp test.c libtool.a
g++ -o testcpp test.c tool.o

readelf -s -W testcpp | grep hello
60: 0000000000400547 41 FUNC GLOBAL DEFAULT 13 _Z5helloiPKc
即使用了_Z5helloiPKc符号信息;

3 结论:extern “C”用法

1、使用g++编译的时候,在C++的代码中使用。即extern “C”是给C++代码编译时使用的,而非C代码编译;
2、无论gcc命令还是g++命令,链接的时候,根据符号表中函数符号进行查找,即在链接之前已经生成需要引用的函数符号名称;
备注:这里测试过程并未用到tool.h头文件,其实在g++编译的时候,只需要添加这个已经包含了extern “C”{} 的头文件,。这种用法相当于C代码库的开发者完成了这种让C++代码来调用自己写的C代码的函数链接方式描述,而无需C++代码开发者额外写extern “C”{}。

猜你喜欢

转载自blog.csdn.net/skytering/article/details/105306165