全局变量实现

Pho*_*ong 17 c compiler-construction variables global-variables

当我写下面的程序时:

档案1:

#include <stdio.h>    
int global;    
void print_global1() {
        printf("%p\n", &global);
}
Run Code Online (Sandbox Code Playgroud)

档案2:

#include <stdio.h>
char global;    
void print_global2() {
        printf("%p\n", &global);
}
Run Code Online (Sandbox Code Playgroud)

档案3:

void print_global1();
void print_global2();
int main()
{
        print_global1();
        print_global2();

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./a.out
0x804a01c
0x804a01c
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

  • 为什么链接器将"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
Run Code Online (Sandbox Code Playgroud)

cod*_*ict 12

gcc不报告任何错误/警告.但是g++.

编辑:

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

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

将您的file2更改为:

char global = 1; // no more tentative...but explicit.
Run Code Online (Sandbox Code Playgroud)

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

通过以下方式使def明确:

int global = 1; // in file1

char global = 1; // in file2
Run Code Online (Sandbox Code Playgroud)

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


Alo*_*hal 5

这与在C中称为"暂定定义"的东西有关.首先,如果你global在file1和file2中分配,你将在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
Run Code Online (Sandbox Code Playgroud)

手册:

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

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