开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
1.假设一个C语言程序有两个源文件; main.c和proc1.c,它们的内容如下图所示。
首先理解一下什么是强符号和弱符号?
1)强符号:函数和已经初始化的全局变量
2)弱符号:未初始化的全局变量
针对强符号和弱符号,链接器会按照如下的规则去处理:
规则1:不允许强符号被定义多次。
规则2:如果一个符号在某个文件当中是强符号,在其它文件是弱符号,那么链接时将选择强符号。
规则3:如果一个符号在所有的目标文件当中都是弱符号,那么链接时将选择占用空间最大的那个。
比如,a.c当中有int a;占4个字节,b.c当中有double a;占8个字节,链接时,将选择double a;
我们也可以通过gcc的“attribute((weak))”来定义任何一个强符号为弱符号,比如:
#include<stdio.h>
#include"b.h"
int i = 10; //i是强符号
_attribute_((weak)) a= 20;//现在a是弱符号
int main()//main是强符号
{
}
1)在上述两个文件中,main.c中的强符号有x、z、main,弱符号有y: proc1.c 中的强符号有proc1,弱符号有x。其中,符号x在main.c和 proc1.c中都有定义,属于多重定义符号。
2)程序执行时,在调用proc1()函数之前,&x中存放的是x的机器数:00000101H,随后两个字节(地址为&y)存放y,它没有初始化,故通常为0;再后面两个字节存放z的机器数:0002H。如下图所示:
在调用proc1()函数以后,因为proc1()中的符号x是弱符号,因此,x的定义以main中的强符号x为准,执行x=-1.5后,便将“一1.5”的机器数BFF8000000000000H存放到了&x开始的8个字节中。即&x中为其低32位的00000000H,&y中为高32位的BFF80000H中的低 16位O000H,&z中为高32位的 BFF80000H中的高16位BFF8H。如下图所示。
因此,最终打印的结果如下:x=0,z=-16392。
3)只要将文件proc1.c中的第1行修改为“static double x;”就可以使得proc1中的x设定为本地变量,从而在proc1.o 的.data节中专门分配存放x的8个字节空间,而不会和 main中的x共用同一个存储地址。因此,也就不会破坏main中x和z的值。
字节所占的位数:
和机器字长及编译器有关系:
所以,int,long int,short int的宽度都可能随编译器而异。但有几条铁定的原则(ANSI/ISO制订的):
1 sizeof(short int)<=sizeof(int)
2 sizeof(int)<=sizeof(long int)
3 short int至少应为16位(2字节)
4 long int至少应为32位。
unsigned 是无符号的意思。
例如: 16位编译器
char :1个字节
char*(即指针变量): 2个字节
short int : 2个字节
int: 2个字节
unsigned int : 2个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
32位编译器
char :1个字节
char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
64位编译器
char :1个字节
char*(即指针变量): 8个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 8个字节
long long: 8个字节
unsigned long: 8个字节
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情