多重定义之三两事

  • Post author:
  • Post category:其他


在几年前,公司有同事问了一个问题.他发现在两个档案中有同名变量的定义,比如在a.c中定义了一个变量x,然后在b.c中发现又定义一个同名的变量x.一般来说,编译程序在编译的时候不是会发生编译错误吗?但是经过编译之后就是没啥事发生,经过后来的逆向分析调查,原因是在b.c中定义的变量x是有加上static关键词,因此编译完之后这个变量x就被冠上local局部的属性,因此就避开了重复定义的编译错误了.然而多重定义的神奇现象还不只这一项,接下来就要在跟各位分享另一现象==弱与强之争==

有两段程序如下:

/*foo.c*/

double x;

void foo()

{

x = -0.0;

}

/*main.c*/

#include <stdio.h>

void foo();

int y = 32700;  //0x7fbc

int x = 32701;  //0x7fbd

int main(int argc, const char** argv) {

foo();

printf(“x = %#x y = %#x\n”, x, y);

return 0;

}

经过编译之后,发现

x = 0 y = 0x80000000

1.怎么不是0x7fbc和0x7fbd? 2.另外在foo.c也定义了一个x同名的变量,也没加上static,为何还能编译过?

这两个问题就要从编译程序对于全局符号分类谈起.针对全局变数,编译程序会输出一组全局符号给组译器,组译器就会针对已初始化和未初始化的全局符号编码在可复位位目标档案中.

    1. 函数和已初始化的全局变量标为强符号
    2. 未出始化的全局变量标为弱符号

链结器根据强符号和弱符号有以下三个规则:

1. 众多相关可重定位目标文件里只能只有一个强符号存在

2. 众多相关可重定位目标文件里有多个弱符号和一个强符号,就以强符号为主

3. 众多相关可重定位目标文件里都是弱符号,就从任意的弱符号中选一个

经过这链结规则就可以解答上面的第二个问题,因为x在foo.c里是弱符号而在main.c里是强符号且这强符号只有一个,因此不会有编译错误.而第一个问题是因为x在foo.c里宣告为double,在一般的系统中,double data所占的内存大小是8 byte就这样一但执行过foo函数,原本在main.c宣告的x和y的植就会被盖掉了,因为在main.c里宣告的x和y是int type.这些多重定义产生的奇异现象,真的不得不多加注意.



版权声明:本文为powq2009原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。