一、定义-defintion
被extern "C"修饰的代码会按照C语言的方式去编译
二、extern "C"使用举例-example
我们都知道,C语言不支持函数重载,只有C++才支持函数重载。下方两个函数就会按照C语言进行编译,由于是重载函数,所以会报错
extern "C" void function(int v1, double v2)
{
cout << "int v1, double v2" << endl;
}
extern "C" void function(double v1, int v2)
{
cout << "double v1, int v2" << endl;
}
int main(int argc, char **argv)
{
function(10,10.0);
getchar();
return 0;
}
三、extern "C"的用武之处在哪?
- 由于C、C++编译方式的不同,这种机制往往用在C\C++混合开发,往往做项目时,可能会用到第三方库:这个库可能是C语言写的,这时候这种机制就很重要。
第三方库math.c文件,提供了一个函数,但用的C语言写的
int sum(int v1,int v2)
{
return v1 + v2;
}
my.cpp自己的cpp工程文件,想要调用math.c里的函数为我所用
int sum(int v1,int v2);
int main()
{
sum(1,1);
getchar();
return 0;
}
- 我还是想要用第三方库里的函数,怎么办呢?这时候就要借助extern “C”
第三方库math.c文件,提供了一个函数,但用的C语言写的
int sum(int v1,int v2)
{
return v1 + v2;
}
my.cpp自己的cpp工程文件,想要调用math.c里的函数为我所用
extern "C" int sum(int v1,int v2);
int main()
{
sum(1,1);
getchar();
return 0;
}
四、extern "C"常用特性
1.C++调用第三方库(含.h&.c文件)
函数如果同时有声明(.h文件)和实现(.c),extern “C"修饰只放在函数声明中,即.c文件实现函数时,可以不用再次修饰。如果.cpp文件引用.h中的C语言函数时:如果.h的函数已经被extern “C"修饰,则直接#include””;如果没有被修饰,则必须extern “C” #include""
- .h头文件中的函数声明没有被extern "C"修饰
AAA.h文件
void func_c();
AAA.c文件
void func_c()
{
}
AAA.cpp文件
extern "C" #include"AAA.h"
int main()
{
func_c();
getchar();
return 0;
}
- .h头文件中的函数声明有被extern "C"修饰
AAA.h文件
extern "C" void func_c();
AAA.c文件
void func_c()
{
}
AAA.cpp文件
#include"AAA.h"
int main()
{
func_c();
getchar();
return 0;
}
有函数声明和实现时,想要某个函数采用C语言编译,最好只在函数声明前采用extern “C” 修饰,在函数实现前不做任何操作
2. C语言也调用第三方库(含.h&.c文件)
由于整个项目C++需要调用第三方库(第三方库是用C语言写的),所以用extern “C” 修饰一下这个第三方库里的函数,即可被C++调用。但,我这个项目里如果有.c文件也需要调用这个第三方库,可以直接调用吗?答案是不能的,因为这个第三方库函数已经被extern “C” 修饰了,而C语言是不认识extern “C” 的。
我希望这个第三方库更加的灵活,即C++调用函数时自动加上extern “C” 修饰;C语言调用,extern “C” 自动去掉
a. #define __cplusplus解释
#define __cplusplus这个宏被默认的编写在C++文件的最开头,用来确认这个文件是cpp文件。只要你是cpp文件,第一行编译器默认给你写了一句#define __cplusplus。
b. #ifdef条件编译
#ifdef 和 #endif // 组合使用,达到条件编译的目的。下方代码的最终结果就是:如果某个cpp文件调用这段代码,才会编译代码段,c文件调用这段代码,不会编译这段代码段,即只读到了一对注释
#ifdef __cplusplus
#endif
AAA.h文件
#ifdef __cplusplus
extern "C" {
#endif
void func_c();
#ifdef __cplusplus
}
#endif
AAA.c文件
void func_c()
{
}
AAA.cpp文件
#include"AAA.h"
因为是c++环境,所以AAA.h里的代码是这样的:
extern "C" {
void func_c();
}
int main()
{
func_c();
getchar();
return 0;
}
other.c文件,也需要调用第三方库AAA.h里的函数
#include"AAA.h"
void func_c();
int main()
{
func_c();
getchar();
return 0;
}
c. 启示
以后凡是用C语言编写的第三方库,最好都要按照下述代码改动.h文件。这样的话,C++和C语言文件都可以调用这个第三方库,不仅不会出错,还会使得代码更加规范
#ifdef __cplusplus
extern "C" {
#endif
void function1();
void function2();
void function3();
void function4();
void function5();
.....
#ifdef __cplusplus
}
#endif
五、不相关学习tips
1.防止某个.h文件被重复include
我们在开发的时候,当代码量很大时,我们可能会在中间include头文件,下面的组合会解决这个问题 #ifndef BBB #define BBB …BBB.h头文件代码 #endif //!BBB
BBB.h文件
某个.cpp文件
#include<BBB.h>
...
可能有很多行代码
...
#include<BBB.h>
...
BBB.h文件
#ifndef BBB
#define BBB
#endif
#include<BBB.h>就相当于把BBB.h文件中的代码全部拷贝一份
某个.cpp文件
#include<BBB.h>
...
可能有很多行代码,然后我忘了前面已经#include<BBB.h>了,我又包含了一遍
...
#include<BBB.h>
...
2.防止某个.h文件被重复include(#pragma)
新建.h头文件时第一行出现的 #pragma once,是为了防止这个.h文件被重复包含,即也是防止cpp文件中多次包含相同的.h文件。#pragma once可以起到和上述相同的作用
#pragma once 会被定义在.h文件的开头,也会起到防止被重复include的错误。但与上面的#ifndef的区别是什么呢?
#pragma once 和 #ifndef + #define + #endif //! 的区别在于,后者什么编译器都支持,而前者则必须保证GCC3.4版本之后的编译器才支持。同时前者只能针对整个头文件,而后者可以针对文件中的部分代码。
|