ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C C++混编

2021-11-15 19:34:41  阅读:224  来源: 互联网

标签:DEFAULT SECTION C++ 0000000000000000 混编 print main LOCAL


本文主要针对工程代码中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

标签:DEFAULT,SECTION,C++,0000000000000000,混编,print,main,LOCAL
来源: https://blog.csdn.net/u011228842/article/details/121340655

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有