extern “C“关键字使用

文章目录extern的含义extern "C"的含义和使用extern的含义extern是用来声明全局变量和函数的,其目的是为了告诉编译器被修饰的全局变量和函数是来自于其他模块,这样对于编译器而言:在编译阶段,编译器认为变量和函数定义在其他地方已经有了,就不会报找不到变量和函数定义的错误。在链接阶段,编译器会去其他链接库中去查找全局变量和函数,如果找不到则会报链接错误。举例如下:moduleA.c中定义全局变量和函数如下:#include "moduleA.h"int AddTwoNum
摘要由CSDN通过智能技术生成

extern的含义

extern是用来声明全局变量和函数的,其目的是为了告诉编译器被修饰的全局变量和函数是来自于其他模块,这样对于编译器而言:

  1. 在编译阶段,编译器认为变量和函数定义在其他地方已经有了,就不会报找不到变量和函数定义的错误。
  2. 在链接阶段,编译器会去其他链接库中去查找全局变量和函数,如果找不到则会报链接错误。

举例如下:
moduleA.c中定义全局变量和函数如下:

#include "moduleA.h"
int AddTwoNum(int a, int b)
{
        return a + b + g_Base;
}

moduleA.h如下:

int g_Base = 100;
int AddTwoNum(int a, int b);

将moduleA单独编译成libmoduleA.so。
然后再在moduleB.c中,如果不声明g_Base和 int AddTwoNum,编译器会报找不到g_Base变量的Error和缺少AddTwoNum函数声明的Warning

#include "moduleA.h"
#include <stdio.h>
int main()
{
        int a = 1;
        int b = AddTwoNum(a, g_Base);
        printf("b = %d\n", b);
}

在添加声明后,编译可以通过

extern int g_Base;
extern int AddTwoNum(int a, int b);

然后在链接阶段,如果moduleB未链接libmoduleA.so,则会报链接失败。
在链接libmoduleA.so后,编译链接都可以通过。

其实对于全局变量和函数而言,其作用域本身就是可以跨函数的,在moduleB.c中即使不加extern,只是简单的重复声明g_Base和AddTwoNum,也可以正常工作。
例如,下面的代码也可以表示在moduleB.c中重新声明全局变量和函数

int g_Base;
int AddTwoNum(int a, int b);

但是下面的处理就会异常,声明可以重复,但是定义只能是唯一的,g_Base不能重复定义,AddTwoNum也不能函数定义冲突。

int g_Base = 100;
int AddTwoNum(int a, int b, int c);

extern "C"的含义和使用

C++支持函数重载,所以编译器在编译C++函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名,例如void testFunc(int a)会被编译成testFunci;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。所以在C++和C混合编程说需要明确告诉编译器调用的函数是C的函数。
extern "C"的含义一方面表示被声明的函数来自于其他模块,另外一方面告诉编译器按照C语言的方式进行函数的编译和链接。
主要使用场景是:
1、C++代码调用C动态库提供的函数
extern "C"可以用来声明具体的函数,也可以直接包含整个C库的头文件。一方面表示函数在其他模块定义,另外一方面提示编译器在链接时按照C的签名方式寻找被调函数
还是以之前的moduleA为例,如果新增的C++代码需要调用libmoduleA.so中的AddTwoNum函数,需要显示声明,否则会链接失败,提示找不到链接的函数。在声明了extern "C"之后,会在链接时按照C的签名方式来寻找被调用的函数。

extern "C" {
	int AddTwoNum(int a, int b);
}

extern "C" {
	#include "moduleA.h"
}

2、C调用C++动态库提供的函数
在C++中用extern "C"声明的函数,在编译时提示编译器按照C的方式生成函数签名。然后再在C语言中调用的时候extern声明外部函数,C语言中不支持extern "C"关键字。
在C++头文件中先声明函数为extern,然后再在cpp文件中定义函数体,这样在编译时就会按照C的方式来生成函数签名

extern "C" {
	int testFunc(int a, int b);
}

通过nm命令可以看到此时生成的库中函数前面变成了 t _GLOBAL__sub_I_testFunc,而不加extern "C"修饰时是t _GLOBAL__sub_I__Z8testFunccc。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值