隐藏于水面之下的extern

extern作用

1、声明变量

2、指定编译和链接的规则

声明变量

怎么C++中,怎么声明一个变量了,或许很多人都不知道

int a;     //错误
int b = 1; //错误

extern val; //正确, 声明一个变量val

很多人可能觉得 like: int a;  这样的语句,就是声明一个变量,其实不是,声明一个变量,表示这个变量是没有内存的,只是告诉编译器,我即将要有一个变量,但是不是现在就需要。

如果是int a 这样的语句,其实a已经有内存地址了,编译器已经给他分配内存了,但是a的值是不确定的,所以需要初始化。

对于extern val 这样的语句,是声明变量的语句,表示这个变量在外部被定义。即在其他文件中提供了这个val变量的定义,我这个文件需要使用val , 就可以使用extern val来声明并使用这个变量。

source1.cpp

int val;
//
source2.cpp

extern val;

可以对这个变量进行操作,对val的修改会影响到source1.cpp的val
即他们是同一个变量.

疑问: 这样的使用场景是什么 ?

总所周知,头文件中是最好不要出现全局变量(no static),不然很容易出现重复定义,因为当这个头文件被一个源文件include 可能没问题,但是当有多个源文件incldue的时候,每个源文件都有这个非static全局变量,所以就会报重定义的错误。

当然,也可以使用条件编译来规避,但是不推荐这样做。特别是做成动态库的时候,头文件全局变量会出现你意想不到的BUG。做法就是将全局变量放在源文件中,所以就使用extern 来声明一个变量吧。

编译和链接的规则

在CPP文件中,只要没有显示的指定(extern "c"),后者都是按照cpp的编译和链接规则来处理的。

什么意思了?

source.cpp

int sum(int a, int b) {
    return a + b;
}

使用C的编译规则,就会生成 一个 sum 的符号函数和变量名就是符号的名称。

如果按照CPP的规则,就会生成一个_Z3sumii的符号。为什么会这样,因为CPP支持函数重载。

当我们看C语言库的时候,就会发现里面的头文件,都会出现extern "c" { ...... }这样的代码,这是什么原因了。让我们分析一下,当C库被cpp文件所使用会出现什么?

上面可知,C库是按照C语言的规则来编译代码的,当C库某一个头文件被CPP文件所include 的时候,就会原地展开,编译的时候,对这些函数的声明等就会按照CPP的规则来编译,当在链接阶段的时候,就会去寻找符号,但是发现找不到,一个是CPP的符号,一个是C的符号,不对应,所以就会报错。那怎么办了,可以在头文件中使用这样

#ifdef  __cpluscplus //是C++宏,在C++文件中有效
extern "C" {
    int sum(int a, int b);
}
#endif

这样就会编译器就知道,当前的头文件是被CPP文件还是C文件所include的,这样当CPP文件所include 并且使用的时候,就会按照C的编译规则来编译出符号啦,这样就能对应C库的sum函数生成的符号,就不会报找不到符号的错误了。

疑问解答:

.h文件

extern "c" {
    int sum(int a, int b);

    int inc(int a) {
        return a + 1;
    }
}

.cpp文件

int sum(int a, int b) {
    return a + b;
}

上面两个函数都是按照C的编译规则,尽管sum函数的定义在cpp文件中。结论就是,只要函数声明是extern "c"的,就得按照C来做。

可以使用nm来查看符号。

2、static 能和extern 来搭配使用吗 ?

不能,static具有跨文件的不可见性,而extern 则希望变量在外部定义,有冲突。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值