全局变量实现

当我写下面的程序时:

档案1:

#include  int global; void print_global1() { printf("%p\n", &global); } 

文件2:

 #include  char global; void print_global2() { printf("%p\n", &global); } 

档案3:

 void print_global1(); void print_global2(); int main() { print_global1(); print_global2(); return 0; } 

输出:

 $ ./a.out 0x804a01c 0x804a01c 

这是我的问题:

  • 为什么链接器将“int global”和“char global”实现为相同的全局变量:
  • 为什么编译器不会抱怨(不是最小的警告-Wall -Wextra -ansi …)
  • 如何管理全局变量的大小(int和char的大小不同)

PS:第二个问题是架构/编译器相关,所以让我们把gcc或Visual C ++(对于C)的int大小为32位

编辑:这不是C ++的问题,但对于C!

我使用gcc版本4.4.1和Ubuntu 9.10,这是编译控制台输出:

 $ ls global_data1.c global_data2.c global_data.c $ gcc -Wall -Wextra -ansi global_data*.c $ ./a.out 0x804a01c 0x804a01c or $ gcc -Wall -Wextra -ansi -c global_data*.c $ gcc -Wall -Wextra -ansi global_data*.o $ ./a.out 0x804a01c 0x804a01c 

gcc不会报告任何错误/警告。 但是g++确实如此。

编辑:

看起来C允许变量的暂定定义

在您的情况下,两个全局定义都是暂定的,在这种情况下,选择链接器看到的第一个定义。

将您的file2更改为:

 char global = 1; // no more tentative...but explicit. 

现在,如果您像以前一样编译,将忽略file1中的暂定def。

通过以下方式使def明确:

 int global = 1; // in file1 char global = 1; // in file2 

现在都不能被忽略,我们得到多重def错误。

这与C中称为“暂定定义”的东西有关。首先,如果你在file1和file2中分配给global ,你将在C中得到一个错误。这是因为global不再在file1和file2中暂时定义,它是真的定义。

从C标准(强调我的):

具有文件范围而没有初始化程序且没有存储类说明符或存储类说明符为静态的对象的标识符声明构成暂定定义 。 如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。

对于你的情况,“翻译单位”(基本上)每个源文件。

关于“复合类型”:

对于在范围内声明的内部或外部链接的标识符,其中该标识符的先前声明是可见的,如果先前声明指定内部或外部链接,则后面声明中的标识符类型将成为复合类型。

有关暂定定义的更多信息,请参阅此问题及其答案 。

看起来对于你的情况,它应该是未定义的行为,因为global是在翻译单元的末尾定义的,所以你得到两个global定义,更糟糕的是,它们是不同的。 看起来默认情况下链接器不会抱怨这一点。

GNU ld有一个名为--warn-common的选项,它会警告您多个暂定定义(常用符号是暂定义变量的链接器名称):

 $ gcc -Wl,--warn-common file*.c /tmp/ccjuPGcq.o: warning: common of `global' overridden by larger common /tmp/ccw6nFHi.o: warning: larger common is here 

从手册 :

如果变量只有(一个或多个)公共符号,则它将进入输出文件的未初始化数据区域。 链接器将同一变量的多个公共符号合并为单个符号。 如果它们的尺寸不同,则选择最大尺寸。 如果存在相同变量的定义,则链接器将公共符号转换为声明。

--warn-common选项可以产生五种警告。 每个警告由一对行组成:第一行描述刚刚遇到的符号,第二行描述遇到的具有相同名称的符号。 两个符号中的一个或两个将是共同的符号。

链接器允许有这样的重复外部数据(虽然我很惊讶不同的类型不会导致问题)。 您获得哪一个取决于链接命令行上的目标文件的顺序。

你在使用哪种编译器。 什么是平台? 用g ++我得到了

 /tmp/cc8Gnf4h.o:(.bss+0x0): multiple definition of `global' /tmp/ccDQHZn2.o:(.bss+0x0): first defined here /usr/bin/ld: Warning: size of symbol `global' changed from 4 in ao to 1 in bo 

AFAIR,在C ++中,不同翻译单元中的变量具有完全相同的声明。