我确信我会发疯,但请考虑以下C代码:
// file1.c
int first;
void f(void)
{ first = 2; }
// file2.c
#include <stdio.h>
int first;
void f();
int main(void)
{
first = 1;
f();
printf("%d", first);
}
这两个文件由于某种原因将编译并链接在一起,并打印2
。我一直认为,除非我用first
标记extern
的一个或另一个(但不是两个)定义,否则这将无法编译,这实际上是{{的全部要点1}}!
答案 0 :(得分:10)
它只会编译因为first
仅声明两次,实际上内存中没有两个位置,只有一个位置。只需先使用int first=4;
初始化一个,然后使用int first=5;
初始化另一个,您的链接器会显示错误,例如GCC:
b.o:b.c:(.data+0x0): multiple definition of `_first'
a.o:a.c:(.data+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
答案 1 :(得分:6)
在正常情况下(没有额外的gcc标志),您可以将此代码编译为:
gcc file1.c file2.c
将会发生的事情是编译器会看到你有两个名为相同的全局变量,并且都没有被初始化。然后,它会将未初始化的全局变量放在代码 ** 的“common”部分中。换句话说,它只有1个“第一”变量的副本。这是因为gcc
的默认值为-fcommon
如果您要使用-fno-common
标记进行编译,那么您现在会收到您正在考虑的错误:
/tmp/ccZNeN8c.o:(.bss+0x0): multiple definition of `first'
/tmp/cc09s2r7.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
要解决此问题,您需要将extern
添加到除一个变量之外的所有变量中。
警告强> 的:
现在假设您有两个不同大小的全局未初始化数组:
// file1.c
int first[10];
// file2.c
int first[20];
好吧猜测一下,用gcc -Wall file1.c file2.c
编译它们会产生没有警告或错误,并且变量很常见,即使它的大小不同!!!
//objdump from file1.c:
0000000000000028 O *COM* 0000000000000020 first
//objdump from file2.c:
0000000000000050 O *COM* 0000000000000020 first
这是全局变量的危险之一。
** 如果您查看* .o文件的objdump
(您必须使用gcc -c
进行编译才能生成它们),您会看到{{1}放置在公共(first
)部分:
*COM*