通常の状態 (追加の gcc フラグなし) では、このコードを次のようにコンパイルしても問題ありません。
gcc file1.c file2.c
コンパイラは、同じ名前の 2 つのグローバル変数があり、どちらも初期化されていないことを認識します。次に、初期化されていないグローバル変数をコードの「共通」セクションに配置します**。つまり、「最初の」変数のコピーは 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
には、1 つを除くすべての変数に追加します。
警告:
ここで、サイズが異なる 2 つのグローバルな初期化されていない配列があるとします。
// 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
これは、グローバル変数の危険性の 1 つです。
**objdump
*.o ファイル (gcc -c
それらを生成するにはコンパイルする必要があります) を見るとfirst
、共通 ( *COM*
) セクションに配置されていることがわかります。
mike@mike-VirtualBox:~/C$ objdump -t file2.o
a.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file2.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata 0000000000000000 .rodata
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000004 O *COM* 0000000000000004 first
0000000000000000 g F .text 0000000000000039 main
0000000000000000 *UND* 0000000000000000 f
0000000000000000 *UND* 0000000000000000 printf