关于extern “C”

废话不多说,直接来看代码。

首先建了一个工程,主函数在cpp文件里,另外用c和c++语言各自实现了一个加法函数add。注意两个源文件的后缀,一个为“.c”,一个为“.cpp”。工程目录文件如下:

主函数如下:

#include <stdio.h>
#include <iostream>
#include "cfunction.h"
#include "cplusfunction.h"


int main(int argc, char* argv[])
{
	std::cout<<add(4, 5)<<std::endl;
	system("pause");
	return 0;
}

我们在c++的main函数里调用c实现的整型加法函数,结果编译时报错如下:

其中,__cdecl是C和C++默认的调用约定,这个与主题无关。

这个报错的意思是add这个函数在被编译器编译后函数名称变成了?add@@YAHHH@Z这个符号而在链接的过程中,main函数去找这个符号的时候找不到。 

下面我们给这个函数加上extern “C”。 cfunction.h如下

/*****************************************************
 Author: zzh
 Mail: 791745123@qq.com
 Time: 2019-2-17
 Function:
	c函数头文件
 Version: v 1.0
*****************************************************/



//写法一
#ifdef __cplusplus
extern "C"{
#endif

	int add(int num1, int num2);

#ifdef __cplusplus
};
#endif


//写法二
//extern "C" int add(int num1, int num2);

 写法一,即如果当前编译单元是c++代码,那么add这个函数就会在extern “C”里声明。写法二则比较直接。

再编译则成功。

为什么加上extern “C”就可以了呢?

我们首先要知道,函数和变量在编译后它们的名称都会转换成一个唯一符号,然后在链接的过程中,调用者根据这个唯一的符号去调用,这种符号是按照一定约定生成的。(详情参考《程序员的自我修养》第三章。)

windows下的编译器会在c语言符号(变量和函数)前加上“_”,即add函数被编译后的符号为_add

 

下面来验证一下。

把C实现的add的定义注释掉,再编译就能看到add被编译后的符号。

报错信息如下

可以看到,符号为“_add”。与之前的报错不同。

Vs编译器下,c++函数编译后的符号规则可参考《程序员的自我修养》第三章。

 

因此,当我们在c++的编译环境中调用c实现的函数时。在编译过程中,c函数add编译后的符号为“_add”,而在c++的main中,add被编译为“?add@@YAHHH@Z”。两个符号不一致,所以就会在链接过程中报错。

一旦将add在extern “c”中声明,在c++的main中,add就被编译为“_add”。这样符号一致,链接器就能找到了。

利用extern “c”使c兼容c++的做法很常见,尤其是在c的库文件中。我们可以打开“stdio.h”这个头文件查看一下。

 这样一来,在我们这个工程里调用这个c的库函数就不会报错了。

调用约定相关介绍请看:https://blog.csdn.net/luoweifu/article/details/52425733

  • 15
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值