コモンは、リンク段階の前にのみ表示されます。Commons は後で bss または data に入るものですが、それがどこに行くかはリンカ次第です。これにより、異なるコンパイル単位で定義された同じ変数を持つことができます。私の知る限り、これはほとんどの場合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
$
これが機能するのは、さまざまなコンパイル ユニット内の変数のうち、多くても 1 つが初期化されている場合のみであることに注意してください。
$ 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
$
これは恐ろしいものであり、古代のシステムとの互換性であり、決してそれに頼るべきではありません. 物事を適切に行います-すべてのコンパイル単位でグローバル変数の定義を1つだけにし、ヘッダーを介して他の場所でexternを宣言します。