extern
前言
C语言和c++对于函数在编译后的处理不同,所以也要注意源文件不要混用
正文
项目里新建俩文件
1 | //main.cpp |
1 | //hh.cpp |
编译的时候就发现报错了:
然后新建两个C语言源文件:
1 |
|
1 | int Ave(int a, int b){ |
编译前先注释掉main.cpp的main函数,因为一个程序只能有一个main函数。
然后就是注释掉hh.cpp的ave函数。
能够看到,函数编译后的结果在.obj文件中时,c++和C语言的函数名都不一样。
显然c++的函数名编译后还是很详细,有类型 函数名 参数 主体之类的,而C语言就加了个下划线
还记得函数重载的话,就会想到这个问题,因为C语言没有函数重载,所以他的函数除了冲突就没用别的要判断,而c++反而因为有了重载,比较起来会更加繁琐。
而你.c和.cpp混用的时候,两个函数在.obj里面的表现不一样,所以编译通过了。
当头文件有声明,.c文件有定义,.cpp调用,同样的也会报错,函数是以C语言的模式编译,cpp就整不明白这个函数了。
所以也要用到extern做声明,extern声明变量应该是在上一章写过了,声明函数的格式:extern "C" int Ave(int a,int b);
或者extern "C"{}
这样主要是有多个函数需要声明的时候可以用花括号套起来。
但是声明归声明,别忘了C语言没有重载,不要做二愣子操作
1 | //emc.h |
1 | //main.cpp |
这样就不需要瞎搞成cpp的函数方式了,直接用c的方法去读就行了。
extren除了套函数声明,还可以直接套头文件:
1 | //main.cpp |
这样操作后,emc.h里面就不需要用extern指定了。
当头文件被.c和.cpp同时调用,函数会被编译成啥鸟样
1 | //main.cpp |
1 | //emc.h |
看到是由extern "C"
发出的错误。
大概就明白extern "C"
这种写法属于c++的,C语言没有这种操作,所以才会报错。
如果真的需要让两个不同的源文件调用,可以用#ifdef
去判断
在c++中有个隐藏的宏定义,__cplusplus
,这样也省得我们去设置宏。
1 | //emc.h |
但更合理的做法感觉是只选extern "C"
那块
1 |
|
因为函数声明都在头文件的前提,只有当源文件类型不同时,才会显示特别的声明。
如果都放在#ifdef
里面,那么C语言文件如果有对函数的定义就会变成既声明又定义了,因为这块内容编译后展开对于C语言源文件不存在。
声明较多的时候感觉这样写也问题不大:
1 |
|
记住C语言没有重载,用extern去用c风格的时候不要带入重载的。
LNK4042
1 | //hh.h |
1 | //hh.cpp |
定义分别在两个源文件中。调用在main.cpp。
这里源文件能重名是因为类型不一样,这种写法不理智,这就举个例子。
所以当编译的时候会将源文件编译成.obj 最后给链接成.exe
当出现重名的源文件时,两个重名的.obj链接就多余了。也就导致了报错。
这个问题其实正常人应该没这无聊去混用这两个。
结语
还是辣句话c++可以这样兼容c语言,但是反过来不行