Commons 只出现在链接阶段之前。Commons 是后来进入 bss 或数据的内容,但由链接器决定它的去向。这允许您在不同的编译单元中定义相同的变量。据我所知,这主要是为了允许其中包含一些古老的头文件,int foo;
而不是extern int foo;
.
以下是它的工作原理:
$ cat > a.c
int foo;
$ cat > b.c
int foo;
$ cat > main.c
extern int foo;
int main(int argc, char **argv) { return foo; }
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ objdump -t a.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t b.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t x | grep foo
0000000000600828 g O .bss 0000000000000004 foo
$
请注意,这仅在不同编译单元中的最多一个变量被初始化时才有效。
$ echo "int foo = 0;" > a.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ echo "int foo = 0;" > b.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
b.o:(.bss+0x0): multiple definition of `foo'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$
这是可怕的东西,与古老的系统兼容,你永远不应该依赖它。正确地做事——所有编译单元中只有一个全局变量定义,通过头文件在其他任何地方声明它。