clang define extern c


原文链接: clang define extern c

extern "C" 在C/C++中的用法

  1. 无论是C++调用C api 还是C调用C++ API, 必须先在API所对应得头文件对API进行 extern "C"声明,并用#ifdef __cplusplus进行保护。
  2. extern "C" 的作用是告诉C++编译器,函数名在编译的时候按照C的格式来进行处理,不要添加冗余的字段。

#ifndef TEST_C
#define TEST_C

#ifdef __cplusplus
extern "C" {
#endif
 
int add(int a, int b);
 
#ifdef __cplusplus
}
#endif 
 
#endif

前言
在重构sample sdk代码,并编译成静态或动态库来提供给上层调用的API时,不可避免会遇到c++调用c或c调用c++的问题。看我博客的网友也提到了这个问题,所以藉这个机会来把C和C++混合编程(即相互调用)的问题透彻的弄清楚。

问题背景
C和C++直接相互调用 之所以会出问题的原因是, C++里面有函数重载的概念,从而导致编译出来的函数名会带上参数类型,而C编译出来的函数名简单的就是其本身。

下面定义了两个简单的c、c++头文件和实现文件

/test_c.h/
#ifndef TEST_C
#define TEST_C

int add(int a, int b);

#endif
/test_c.c/
#include "test_c.h"

int add(int a, int b)
{

int c;
c = a + b;
return c;

}
 

/test_c++.h/
#ifndef TEST_C_PLUSPLUS
#define TEST_C_PLUSPLUS

int substract(int a, int b);

#endif
/test_c++.cpp/
#include "test_c++.h"

int substract(int a, int b)
{

int c;
c = a - b;
return c;

}
 分别使用两个命令生成obj文件。

gcc -c test_c.c
gcc -c test_c++.cpp
然后使用命令: nm test_c.o | grep add  和  nm test_c++.o | grep substract 得到如下结果:

add 和 _Z9substractii。  这个结果进一步验证了前面所说的,即C和C++编译出来的函数名会不一样。

C调用C++ 
添加一个C测试文件main.c,并调用add和substract API。

/main.c/
#include
#include "test_c.h"
#include "test_c++.h"

int main(void)
{

int x = 3;
int y = 5;

printf("add = %d \n", add(x, y));
printf("sub = %d \n", substract(x, y));

return 0;

}
使用命令如下来将它们编译成一个可执行文件test_c:

gcc test_c.c test_c++.cpp main.c -o test_c
但这个时候会报链接错误: main.c:(.text+0x43): undefined reference to 'substract' 。明明我们在test_c++.cpp里面定义了substract(),但是main.c不识别。 这也说明了 c直接调用c++代码出现错误。

解决办法就是引入 extern "C"。 关于它有两个重要注意点:

1)extern "C"是c++语法,只能被c++编译器认识,其目的就是告诉C++编译器,其被extern "C"所包含的函数得以C方式(即简单函数名)去链接。

2) 为了避免C编译器来编译它来产生编译错误, 保险起见,会将 extern "C" {和}用#ifdef _cplusplus... #endif修饰起来。这里很容易犯得一个错误就是 cplusplus前面是两根下划线""。

回到上面得错误,我们得在test_c++.cpp编译时,得用c方式去来生成substract函数。所以test_cpp.h更新如下,并用__cplusplus保护起来,避免main.c编译时报错。

/test_c++.h/
#ifndef TEST_C_PLUSPLUS
#define TEST_C_PLUSPLUS

#ifdef __cplusplus
extern "C" {
#endif

int substract(int a, int b);

#ifdef __cplusplus
}
#endif

#endif
再次编译链接: gcc test_c.c test_c++.cpp main.c -o test_c没有问题,并执行./test_c 结果也完全正确。

C++调用C
添加一个C++测试文件main.cpp来调用add和substract。

/main.cpp/
#include
#include "test_c.h"
#include "test_c++.h"

int main(void)
{

int x = 3;
int y = 5;

printf("add = %d \n", add(x, y));
printf("sub = %d \n", substract(x, y));

return 0;

}
使用类似命令来编译链接: gcc test_c.c test_c++.cpp main.cpp -o test_cpp,结果也出现main.cpp里面找不到定义在test_c.c里面得add函数。

同样地,必须在test_c.h里面添加extern ”C“来告诉main.cpp编译链接时得以c方式来寻找add函数。同时使用__cplusplus修饰避免 test_c.c编译失败。

/test_c.h/
#ifndef TEST_C
#define TEST_C

#ifdef __cplusplus
extern "C" {
#endif

int add(int a, int b);

#ifdef __cplusplus
}
#endif
#endif
使用编译链接命令:gcc test_c.c test_c++.cpp main.cpp -o test_cpp 没有问题,并执行./test_cpp 结果也完全正确。

结论
无论是C++调用C api 还是C调用C++ API, 必须先在API所对应得头文件对API进行 extern "C"声明,并用#ifdef __cplusplus进行保护。
————————————————
版权声明:本文为CSDN博主「ltshan139」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/avideointerfaces/article/details/97765339

`