More Effective C++ 条款34 如何在一个程序中结合C++和C

1. C++和C混合使用的前提之一就是编译器产生兼容的目标文件(.lib和.dll等).所谓"兼容",指的是编译器在"预编译器相依的特性上"一致,如int和double大小,参数压栈机制等,只有在这个基础上才能讨论结合使用C++和C模块的问题.

2. 在1的基础上,要结合使用C++和C的模块,主要有以下几点需要注意:

    1). name mangling(名称重整)

    Name mangling是C++用于支持函数重载的机制,它对重载的函数名称进行一定改变,使得每个函数具有独一无二的名称,由于C不支持函数重载,因此也就不需要name mangling.

    如果C++要调用C函数库的某个函数,如果不抑制name mangling,经由name mangling后的函数名称可能与C函数库的原函数名称不匹配,因此就会导致链接失败.解决方法就是使用extern C阻止name mangling,像这样:

extern "C" 
void simulate(int iterations);

    这样C++编译器在编译C++文件时就会避免对simulate进行name mangling,转而采用和C相同的命名方式.extern "C"只对接下来的一个函数有效,如果要同时为多个函数使用extern "C",可以使用中括号:

extern "C" { 
    void drawLine(int x1, int y1, int x2, int y2);
    void twiddleBits(unsigned char bits);
    void simulate(int iterations);
    ...
}
View Code

    有时代码既有可能被C++使用也有可能被C使用:当用于C++时,可能需要使用extern "C",而用于C时不需要,可以利用C++预定义的的__cplusplus宏使得文件可以"通用于数种语言",像这样:

#ifdef __cplusplus
extern "C" {
#endif
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
...
#ifdef __cplusplus
}
#endif
View Code

    (注:如果要结合使用C,assembler,Fortran,LISP,Forth等的函数库,也需要抑制name mangling而使用extern "C".并没有像extern "Fortran"这样的用法,因为extern "C"并不说函数以C写成,而是指明要抑制name mangling. )  

    具体用法参照:http://www.cnblogs.com/luxiaoxun/p/3405374.html 

    2). Statics的初始化

    程序的入口实际上并不是main,而是编译器提供的特殊函数(如 mainCRTStartup(void)等,见C/C++:对象初始化相关),在mainCRTStartup主要任务之一就是全局对象(包括static class对象,全局对象,namespace作用域内的对象以及文件作用域内的对象)的初始化工作,由于C++支持动态初始化(如全局变量int b=a;)而C仅支持静态初始化(见C/C++:对象初始化相关),因此全局对象的动态初始化涉及到动态初始化就应该在C++中撰写main,而将C main重命名为realMain,然后让C++ main调用realMain,像这样:

extern "C" // implement this
int realMain(int argc, char *argv[]); // C程序库的函数,用于完成主函数功能
int main(int argc, char *argv[]) // C++代码
{
return realMain(argc, argv);
}
View Code

    3). 动态内存分配

    C动态内存分配和释放使用malloc(及其变种)和free函数,只涉及内存的分配和释放;而C++使用new和delete关键字,并自动调用对象的构造函数.malloc(及其变种)/free搭配使用,new/delete搭配使用,不能混淆.

    (注:个人认为只要彻底了解new和delete的内部机制,混用问题也不大,见Effective C++ 条款16)

    4). 数据结构的兼容性

    C和C++对于struct和内置类型变量是兼容的,因为C/C++对于struct的内存布局相同,但如果C++为struct加上非虚成员函数,由于struct内存布局不改变,其对象仍兼容于C,但如果加上虚函数,由于vtbl和vptr的存在,struct内存布局便发生改变,也就不再兼容于C.

    也就是说,在C和C++之间对数据结构做双向交流是安全的——前提是结构的定义式在C和C++中都可编译;如果为C++ struct加上非虚函数,虽然不再兼容于C,但可能不影响兼容性;其他改变如虚函数和继承等则会产生影响.

posted @ 2015-10-14 21:15  Reasno  阅读(336)  评论(0编辑  收藏  举报