C C++混编
2021/11/15 22:12:15
本文主要是介绍C C++混编,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本文主要针对工程代码中C和C++混编需要注意的一个点进行记录。
示例代码如下所示:
编译结果如下所示:
[... demo]$ ./build.sh -- Configuring done -- Generating done -- Build files have been written to: /home/10260390@zte.intra/桌面/demo/build [ 33%] Building C object CMakeFiles/hello_world.dir/main.c.o [ 66%] Building C object CMakeFiles/hello_world.dir/print.c.o [100%] Linking C executable hello_world [100%] Built target hello_world
对于以上纯C语言代码的工程来说并没有什么问题。
接下来我们把 main.c 文件的名字改为 main.cc,文件内容保持不变,重新编译。
[... demo]$ mv main.c main.cc [... demo]$ ./build.sh -- Configuring done -- Generating done -- Build files have been written to: /home/10260390@zte.intra/桌面/demo/build Scanning dependencies of target hello_world [ 33%] Building CXX object CMakeFiles/hello_world.dir/main.cc.o [ 66%] Building C object CMakeFiles/hello_world.dir/print.c.o [100%] Linking CXX executable hello_world CMakeFiles/hello_world.dir/main.cc.o:在函数‘main’中: main.cc:(.text+0x5):对‘print()’未定义的引用 collect2: 错误:ld 返回 1 CMakeFiles/hello_world.dir/build.make:117: recipe for target 'hello_world' failed make[2]: *** [hello_world] Error 1 CMakeFiles/Makefile2:94: recipe for target 'CMakeFiles/hello_world.dir/all' failed make[1]: *** [CMakeFiles/hello_world.dir/all] Error 2 Makefile:102: recipe for target 'all' failed make: *** [all] Error 2
发现会报 main.cc:(.text+0x5):对‘print()’未定义的引用 的错误。究其原因,是C语言和C++符号修饰机制不同导致的这个问题。
下面我们通过分解工程编译的步骤来深入剖析这个问题的本质。
[... demo]$ gcc -c print.c -o print.o [... demo]$ g++ -c main.cc -o main.o [... demo]$ readelf -s print.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 print.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 17 FUNC GLOBAL DEFAULT 1 print 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts [... demo]$ readelf -s main.o Symbol table '.symtab' contains 10 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.cc 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 6 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 16 FUNC GLOBAL DEFAULT 1 main 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z5printv
可见在 print.c 编译得到的重定位目标文件 print.o中 print 会被修饰为 print, 而 main.cc 编译得到的重定位目标文件 main.o 中 print 会被修饰为 _Z5printv。由于链接时会对外部函数的引用进行重定位,因此需要在全局符号表中寻找_Z5printv,找不到就会报未定义的错误。
对于这种问题,有一种通用的解决方式,即在头文件 print.h 中使用 extern ”C“。但有个问题是。C语言并不支持 extern ”C“ 语法,如果为了兼容 C 语言和 C++ 而定义两个头文件又太麻烦。幸好我们有一种很好的方法解决上述问题,那就是使用 C++ 的宏 __cplusplus,C++ 编译器会在编译 C++ 程序时默认定义这个宏,程序中就可以用这个条件宏来判断当前编译单元是否为 C++ 源文件。具体代码如下:
#ifndef _PRINT_H #define _PRINT_H #ifdef __cplusplus extern "C" { #endif void print(); #ifdef __cplusplus } #endif #endif
重新编译,无论 print.h 被 C 语言源文件还是被 C++ 源文件包含,print 都会按照 C 语言的方式进行符号修饰,自然就不会再报符号未定义的错误了。
[... demo]$ g++ -c main.cc -o main.o [... demo]$ readelf -s main.o Symbol table '.symtab' contains 10 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.cc 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 6 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 16 FUNC GLOBAL DEFAULT 1 main 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND print
这篇关于C C++混编的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-07-06有没有什么开源的py项目可以对图像进行分类-icode9专业技术文章分享
- 2024-07-05feign默认connecttimeout和readtimeout是多少-icode9专业技术文章分享
- 2024-07-05idea控制台,日志太多,导致部分想看得日志被刷走 搜不到-icode9专业技术文章分享
- 2024-07-05The server selected protocol version Tls10 is not accepted by client preferences [TLs12]-icode9专业技术文章分享
- 2024-07-05怎么清理项目缓存-icode9专业技术文章分享
- 2024-07-04安装 Eyoucms详细图文教程-icode9专业技术文章分享
- 2024-07-04ueditor 复制文章时,图片的链接是一个下载图片地址,该如何处理?-icode9专业技术文章分享
- 2024-07-04怎样判断host有没有对wordpress有缓存呢-icode9专业技术文章分享
- 2024-07-04具有编译功能的系统make后,无法ssh连接-icode9专业技术文章分享
- 2024-07-04make后如何升级ssh-icode9专业技术文章分享