链接器如何解析 C 中多重定义的全局符号

问题描述 投票:0回答:2

我的教科书是这么说的:

“函数和初始化的全局变量获得强符号。未初始化的全局变量获得弱符号。给定一个强符号和多个弱符号,选择强符号”

所以我创建了两个文件来查看:

文件1.c:

int number;

int main(int argc, char *argv[]) 
{
    printf("%d",number);
    return 0;
}

file2.c(只有一行):

int number = 2018;

我运行了

gcc -Wall -o program file1.c file2.c
,输出是0,在我研究链接器之前我可以理解(file1.c中的'number'已初始化为0),但是在我研究链接器如何工作之后,我开始想知道为什么输出不是 2018,因为 file2 中的“number”是强符号(初始化的全局变量),而 file1 中的“number”是弱符号,因此链接器会选择值为 2018 的强符号,那么为什么链接器选择弱符号?

c linker operating-system static-linking
2个回答
4
投票

file1.c 中的

int number;
并非未初始化。请注意,它是在文件范围内声明的,声明时没有初始化程序,并且声明时没有存储类说明符(特别是没有
extern
static
)。然后 C 2018 6.9.2 2 说:

具有文件范围且没有初始化程序、没有存储类说明符或带有存储类说明符

static
的对象的标识符声明构成了暂定定义。如果翻译单元包含标识符的一个或多个临时定义,并且翻译单元不包含该标识符的外部定义,则行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元末尾的初始值设定项等于 0。

因此,出于初始化目的,file1.c 中的

int number;
int number = 0;
相同。已初始化。

您引用的文本的一个问题是,它使用该链接器的术语来描述链接器,这与 C 标准使用的术语不同。 C 标准没有任何“全局”变量或“强”或“弱”符号。


0
投票

file2.c 中的

number
是全局的,但仍仅限于该文件的本地范围。如果您希望 file1.c 使用 file2.c 中的
number
,您需要将其标记为
extern
,如下所示:

extern int number;

int main(int argc, char *argv[]) 
{
    printf("%d",number);
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.