在这个例子中,
在main.c中,整形全局变量d被初始化为100 ,作为强符号;在p1.c中,双精度浮点型全局变量d没有初始化,作为弱符号。链接时链接器选择强符号而不是弱符号。
而在函数p1中,d被赋值为双精度型1.0,二进制数表示为0 01111111111 0…0。因为(int)d是强符号,(double)d是弱符号,所以赋值给(int)d。又因为d为int类型,占32位,而double 1.0占64位,按照小端格式存储时,这个64位的二进制数会向高地址溢出,造成写覆盖,所以最后结果是:
把d赋值为0x0000 0000,在给d赋值的同时不小心也把x覆盖成了0x3FF0 0000
最后打印输出的结果就是:d=0,x=1072693248
栈上的存储情况如下表所示:
地址 | 栈 |
0x4014 | x |
0x4010 | d |
在虚拟机上实际操作一下:
发现产生了一条警告信息:/usr/bin/ld: warning: alignment 4 of symbol `d' in main.o is smaller than 8 in p1.o
查阅资料得知:
这条警告信息来自链接器(ld),它是在链接一个或多个目标文件(例如main.o和p1.o)以创建最终的可执行文件或库时产生的。
警告信息的内容是关于符号(在这个例子中是d)的对齐(alignment)问题。在计算机系统中,内存对齐是为了提高访问内存的速度和效率而设置的一种策略。处理器在访问对齐的内存地址时通常会比访问未对齐的内存地址更快。
这条警告信息的具体含义是:
在main.o这个目标文件中,符号d的对齐要求是4字节(即它的地址应该是4的倍数)。
但在p1.o这个目标文件中,对于同一个符号d(这通常意味着它在两个文件中都被定义了,可能是全局变量或函数),它的对齐要求是8字节(即它的地址应该是8的倍数)。
由于链接器在合并这些目标文件时需要确定每个符号的最终地址,它会选择更大的对齐要求来确保所有的引用都能正确地工作。在这个例子中,它会选择8字节的对齐要求。
这也就解释了为什么赋值成的1.0是64位的。
gdb调试查看变量x和d的地址:
与上面表中一致。