首页 > 技术文章 > extern "C" 问题

create-serenditipy 2021-08-26 22:15 原文


链接:https://www.zhihu.com/question/265637582/answer/303612042

  首先讲讲语法:不是“函数外边包一层extern "C" {....}”这样子。你只需要在函数的声明上面加一个extern "C"就行了,如果有多个函数需要声明,就再加个{}一起搞定。记住是函数的声明,不是函数定义,所以一般extern "C"放在头文件内。当然你非要函数定义上加extern "C"也可以,只是要注意要和前面头文件内的申明一致。

  然后是原理:

  C编译器编译代码生成的obj文件的符号表内,函数名称保持原样,比如int add(int,int)函数在符号表内就叫做add;C++编译器编译C++代码生成的obj文件符号表内,因为有overload的存在,函数名称的符号不再是原来的比如add,而是类似_Z3addii这样的(这是我的g++结果)。那么,一个C程序需要使用某个C++库内的add函数时,C程序这边期望的是add,但C++库内是_Z3addii这样的,不匹配嘛对不对,所以链接阶段要报错,说找不到add这个函数。

  同样,一个C++程序需要使用某个C库内的add函数,C++程序这边期望的是_Z3addii,但C库内是add这样的,同样不匹配,链接阶段也是报错,这次是说找不到_Z3addii。

  extern "C"的意思,是让C++编译器(不是C编译器,而且是编译阶段,不是链接阶段)在编译C++代码时为被extern “C”所修饰的函数在符号表中按C语言方式产生符号名(比如前面的add),而不是按C++那样的增加了参数类型和数目信息的名称(_Z3addii)。

  展开来细说,就是:

  如果是C调用C++函数,在C++一侧对函数声明加了extern "C"后符号表内就是add这样的名称,C程序就能正常找到add来调用;如果是C++调用C函数,在C++一侧在声明这个外部函数时,加上extern "C"后,C++产生的obj文件符号表内就也是标记为它需要一个名为add的外部函数,这样配合C库,就一切都好。

  总结:

  不管是C代码调用C++编译器生成的库函数,还是C++代码调用C编译器生成的库函数,都需要在C++代码一侧对相应的函数进行extern “C”申明。   

推荐阅读