程序员的自我修养 8.8分
读书笔记 目标文件里有什么
knightley
C++为了与C兼容,在符号的管理上,C++有一个用来声明或定义一个C的符号的"extern "C""关键字的用法:
extern "C" {
int func(int);
int var; }
C++编译器会将在extern "C"的大括号内部的代码当作C语言代码处理。所以很明显,上面的代码中,C++的名称修饰机制将不会起作用。它声明了一个C的函数func,定义了一个整型全局变量var。从上文中我们得知,在Visual C++平台下会将C语言的符号进行修饰,所以上述代码中的func和var的修饰后符号分别是_func和_var;但是在linux版本的GCC编译器下却没有这种修饰,extern "C"里面的符号都为修饰后符号,即前面不用加下划线。如果单独声明某个函数或变量为C语言的符号,那么也可以使用如何格式:
extern "C" int func(int);
extern "C" int var;
上面的代码声明了一个C语言的函数func和变量var。我们可以使用上述的机制来做一个小实验。。。。。。
很多时候我们都会碰到有些头文件声明了一些C语言的函数和全局变量,但是这个头文件可能会被C语言代码或C++代码包含。比如很常见的,我们的C语言库函数中的string.h中声明了memset这个函数,它的原型如下:
void *memset(void*, int, size_t);
如果不加任何处理,当我们的C语言程序包含string.h的时候,并且用到了memset这个函数,编译器会将memset符号引用正确处理;但是在C++语言中,编译器会认为这个memset函数是一个C++函数,将memset的符号修饰成_Z6memsetPvii,这样连接器就无法与C语言库中的memset符号进行链接。所以对于C++来说,必须使用extern "C"来声明memset这个函数。但是C语言又不支持extern "C"语法,如果为了兼容C语言和C++语言定义两套头文件,未免过于麻烦。幸好我们有一种很好的方法可以解决上述问题,就是使用C++的宏“__cplusplus”,C++编译器会在编译C++的程序时默认定义这个宏,我们可以使用条件宏来判断当前编译单元是不是C++代码。具体代码如下:
#ifdef __cplusplus
extern "C" {
#endif
void *memset (void*, int, size_t);
#ifdef __cplusplus
}
#endif
如果当前编译单元是C++代码,那么memset会在extern "C"里面被声明;如果是C代码,就直接声明。上面这段代码中的技巧几乎在所有的系统头文件里面都被用到。

extern "C"这个用法是笔试面试中会考到的地方。这一小节对extern "C"的知识点介绍的很详细,并且有例子说明。并且对于memset这个例子中extern "C"的用法,是当前各种系统头文件中的实际用法,很有说服力。

0
《程序员的自我修养》的全部笔记 294篇
豆瓣
免费下载 iOS / Android 版客户端