Extern "C"的作用解析

       曾经在面试的时候被问过C和C++的交互,当时笔者对于这个问题基本没有什么概念,所以回答的很差,最后直接导致了面试的失败。所谓知耻而后勇,不断地从失败中总结可以让自己更快地成长,最终也将取得成功。这篇博客所讲的Extern "C"就是C和C++进行交互的一个途径。笔者在阅读了《深度探索C++对象模型》和《程序员的自我修养》这两本书之后,决定对Extern "C"进行一下解释,有不对之处希望阅读者能够交流。

       有过C/C++面试经历的同学想必十有八九都被问过这样一个问题,就是C和C++的区别,其中一个区别就是C++可以支持函数重载,而C却不可以,这是因为C++在编译时,会对函数名做特殊处理,《深度探索C++对象模型》一书中称之为“name mangling”,实际上编译过的函数名一般会包含函数名称+参数数目+参数类型,不同的编译器处理是不一样的。而C语言在编译的时候并没有做类似的处理,所以C不支持函数重载而C++却可以,就是因为在C中,即便函数参数列表不同,编译过后的函数名依然是一样的,如果依然想实现函数重载,就会编译错误。

       那么这个“name mangling”和Extern "C"又有什么关系呢?我们可以看下面这种情况,一个规模较大的软件,有一个库是用C写的,使用这个的模块则是用C++写的,假如我们要在这个模块中使用这个C语言库中的一个函数,那么直接使用在链接的时候就会报错,Extern "C"就是来解决这个问题的。徒说无益,笔者自己写了一个程序用来验证,以下是程序的组织,非常简单,就是一个C++的.cpp文件调用C的.c文件中的一个函数:

让我们看看每个文件中的内容:

C_Fun.h

#pragma once

//#ifdef __cplusplus
//extern "C" {
//#endif

void func_print();

//#ifdef __cplusplus
//}
//#endif

C_Fun.c

#include <stdio.h>
#include "C_Fun.h"

void func_print()
{
	printf("This a function from C_lib!\n");
}

Test_Main.cpp

#include "C_Fun.h"

//extern "C" void func_print();

int main()
{
	func_print();

	return 0;
}

然后我们编译,报错了,是一个链接错误,错误如下

原因就是因为此处func_print函数的实现是在一个.c文件中,则会按照C语言的编译规则对函数名进行处理,那么就会导致链接错误,我们可以用VS2008自带的dumpbin工具查看两个.obj文件,即可直观地分析这个错误的原因,首先打开VS2008工具的命令行功能,然后用cd指令进入到工程的debug目录,接着使用dumpbin将.obj文件中的内容复制到.txt文件中,方便我们查看。具体操作如下:

我们先看得到的C_Fun.txt文件中的内容,让我们略过一些和本篇文章关系不大的内容,直接看符号表,别的笔者以后的文章中将会进行讲解:

请注意红框标示的那一行,notype()表示这是一个函数的符号,External表示该符号具有外部链接属性,即别的目标文件可以引用该符号,最后我们发现,按照C编译规则编译过后的函数名就是在前面加上了_而已,成了_func_print。

接下来是Test_Main.txt中的符号表:

依然请关注红框所示,符号名就是我们刚才看到那个链接错误的符号名,还要解释一下这里的UNDEF,表示符号是未定义的,这个符号定义在其他目标文件,但是链接器到C_Fun.obj中查找该符号却没有找到,因为C_Fun.obj中该函数在编译后成了_func_print,所以报错了,那么我们现在把C_Fun.h中代码的注释去掉(请看上面的图片),然后重新编译,结果就是编译通过了,我们再看看两个目标文件符号表中的这两个函数,还是采用如上所述的方法:

C_Fun.txt中

Test_Main.txt中

现在可以看到,两个目标文件中的函数名一样了,这是因为Extern "C"压抑了“name mangling”,在Test_Main.cpp编译时对func_print函数用C语言的编译规则进行了编译。

        关于Extern "C",先讨论到这边,实际上这是针对两种语言的不同之处提出的一种兼容的方法,如有疑问和补充,欢迎补充,转载请注明出处。





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值