C/C++ extern “C“ 的问题
声明
文章中的部分代码引用来在:
https://blog.csdn.net/u012234115/article/details/43272441
场景
今天在CSDN中看到了一篇关于 extern “C” 相关的文章, 这让我想起了之前解决相关问题的场景。
具体如下:
PC端图形工具是基于QT开发的,控制端使用MCU开发。因为有某些代码需要和PC端共享,所以该段代码是用C写的。当PC端合入该代码后发现总是编译报错。后来发现是C代码那边并没有考虑C++的场景。也许很多MCU开发者都不会考虑这个问题。而实际上好的代码一般都不会存在这个问题。
为什么
是不是经常在大型C项目的 .h 中看到如下的代码:
#ifdef __cplusplus
extern "C"
{
#endif
//一段代码
#ifdef __cplusplus
}
#endif
我们知道C++是可以兼容C代码的,.h 文件其实是C的头文件,这种写法的目的是当C文件用于C++项目时告诉编译器这是C文件。
具体如下:
__cplusplus这个关键字是C++中特有的, 当定义了该宏就表示这是C++环境。(具体这个定义的含义因编译和C++标准不同而有所不同但是这里不重要)。如代码所示如果是C++环境即加入extern “C” 。
要明白为何使用extern "C",还得从C++中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等。而在C中,只是简单的函数名字而已,不会加入其他的信息,也就是说 C++和C对产生的函数名字的处理是不一样的。
如下一段简单的代码,对比加入和不加入extern "C"产生的汇编代码:
int f(void)
{
return 1;
}
加入extern "C"时候产生的汇编代码:
.file "test.cxx"
.text
.align 2
.globl _f
.def _f; .scl 2; .type 32; .endef
_f:
pushl %ebp
movl %esp, %ebp
movl $1, %eax
popl %ebp
ret
不加入extern "C"产生的汇编代码:
.file "test.cxx"
.text
.align 2
.globl __Z1fv
.def __Z1fv; .scl 2; .type 32; .endef
__Z1fv:
pushl %ebp
movl %esp, %ebp
movl $1, %eax
popl %ebp
ret
两段汇编代码同样都是使用gcc -S命令产生的,所有的地方都是一样的,唯独是产生的函数名,一个是_f,一个是__Z1fv。
总结
工作中发现一些朋友并不清楚甚至不知道extern ”C"的作用。这或许与个人的开发领域单一有关,用心观察会发现一些MCU的库头文件其实都有这些标注。
努力吧!