Поскольку вы связываете файлы запуска со своей программой, которая содержит (обычно) код ассемблера, вызывающий ваш 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
У вашего поставщика инструментов будет служебная программа, которая сделает это. Например. objdump (Unixy), dumpbin (MSFT), tdump (Borland / CodeGear / Embarcadero)
Хорошо, хорошо, спасибо, ребята, за ваши объяснения. Это очень помогло мне узнать
Отличный ответ. Очень понравилось
Также есть «nm» для Unix. objdump более мощный инструмент, но вам нужно понимать его параметры.
Настоящая отправная точка кода похоронена в библиотеке времени выполнения C. Эта библиотека времени выполнения вызывает вашу подпрограмму main (). Чтобы компоновщик мог связать вызов C RTL с вашей функцией main (), он должен быть видимым вне файла.
Внешняя связь такова: это означает, что рассматриваемое имя отображается как часть экспорта объектного файла. Задача компоновщика - объединить весь импорт и экспорт, чтобы не было невыполненных операций импорта.
Как мы можем проанализировать эти единицы перевода. Можем ли мы увидеть их в виде таблиц или графических форм для каждого файла? Если это невозможно, то в каком файле, созданном компилятором, или файле атрибутов, мы можем узнать атрибут функции.?