Потому что вы связываете файлы запуска с вашей программой, которая содержит (как правило) код ассемблера, который вызывает ваш main. Если бы main был статическим, этот код не смог бы вызвать main.
external linkage
означает, что другие так называемые translation-units
могут видеть ваш символ, объявленный extern в своей собственной единице перевода. Итак, ваш main - это extern, и в его таблице символов единиц перевода будет запись, в которой будет указан его адрес. Другие переводчики смогут перейти по этому адресу, когда захотят вызвать main.
static linkage
означает, что ваш символ является строго локальным переводом. Это означает, что другие translation units
не смогут увидеть этот символ. Таким образом, символы со статической связью могут встречаться в разных единицах перевода несколько раз, и они не будут конфликтовать друг с другом, потому что они локальны.
Редактировать : Как правило, файлы, сгенерированные компилятором из единиц перевода, являются специфическими для этого конкретного компилятора. Для gcc в linux часто используется формат объекта ELF. Вы можете просмотреть его таблицу символов, используя readelf -sW <file>.o
(простой тестовый файл ниже):
test.c
void bar(void);
static int foo(void) {
return 1;
}
int main(void) {
bar();
return foo();
}
Вот вывод readelf:
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS test.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 10 FUNC LOCAL DEFAULT 1 foo
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 5
8: 0000000a 36 FUNC GLOBAL DEFAULT 1 main
9: 00000000 0 NOTYPE GLOBAL DEFAULT UND bar
Вы видите функцию main и статическую функцию foo, вызываемую main. Также есть функция, которая не определена в файле, но определена в другом объектном файле. Поскольку объектный файл еще не был окончательно связан, функциям еще не назначены конечные адреса. После последней ссылки они будут размещены в исполняемом файле и будут иметь назначенные адреса. В объектном файле есть записи для вызовов еще не определенных функций, поэтому при связывании файла в этих инструкциях вызова могут храниться конечные адреса (readelf -r <file>.o
):
Relocation section '.rel.text' at offset 0x308 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
0000001c 00000902 R_386_PC32 00000000 bar