全局变量的重复定义会怎样?

有些人的第一反应是编译不过吧?

//fun.c
void func()
{
    printf("测试1");
}

//main.c
void func()
{
    printf("测试2");
}
void main()
{
    func();
}

编译:

这里可以看到保存错了,因为func重复定义了。

但是重复定义就会全部错误吗?并不全是

看下边代码:

//ver.c
int num;
void change()
{
    num = 1023;
}
//main.c
#include <stdio.h>
void change();
int num = 1024;
int main(void)
{
    printf("before:num is %d\n",num);
    change();
    printf("after:num is %d\n",num);
    return 0;
}

输出结果:

before:num is 1024 
after:num is 1023

从结果中可以看到,虽然num被定义了两次,但是任然可以编译通过,并且可以正常运行,这又是为什么呐?

·这就需要引出{ 符号 }

符号:

在了解符号之前,可以先了解一下GCC的编译过程,ELF文件生成的最后阶段都会经历链接,而链接阶段正是基于符号才能完成的。每个目标文件都会有一个符号表。而且链接过程正是通过符号表中的符号,将不同的文件“粘贴”在一起,最后形成库或者可执行文件。要查看目标文件的符号信息也挺容易。

// symbol.c
#include <stdio.h>
int symbel = 1024;
int func_symbel()
{
    return 0;
}

编译:

$ gcc smbol.c #编译
$ nm symbol.o #查看符号信息
0000000000000000 T func_symbol
0000000000000000 D symbol

弱符号和强符号

对于C/C++语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。当然也可以通过

_attribute__((weak))

去定义一个强符号为弱符号

通过下边的例子来说明那些是强符号哪一些树弱符号:

#include <stdio.h>
int weak;//未初始化全局变量为弱符号
int strong = 1024;//已经初始化全局变量,强符号
_attribute__((weak)) int weak1 = 2222;//使用标识修饰弱符号

注意: 这里的强弱符号都是针对于指针定义来说的

 同名时候用哪一个?

  对于多重定义,即标题提到的变量重名的时候,链接器有自己的处理规则:
  1、强符号不允许重复
  2、有一个强符号和多个弱符号使用强符号
  3、多个弱符号,则随便选择一个

关于第一点,在最开始的例子中你已经见到了,最常见的情况就是你重复定义了变量或者函数等等。

而第二点也有示例,示例中,虽然定义了两个num,但是var.c中未初始化的num是弱符号,main.c中的num是强符号,这种情况下编译正常。只是最终会使用强符号的num。

再看一个第三点的例子也是类似,当其中main.c的num无初始化时,也是可以编译过的。这种情况下的误用也就罢了,如果是重复的符号,但是类型不同,问题就更大了,即var.c的内容如下:

//var.c
double num;
void change()
{
    num = 1023;
}

这里的num变成了double,再次编译运行,你会发现意想不到的结果:
为什么修改后是0?原因在于double类型的数据存储与int类型数据存储格式不一样,且它们占用空间长度都不一样,在本文例子中,double占用8字节,而int占用4字节。

来源:公众号【编程珠玑】
作者:守望先生
ID:shouwangxiansheng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值