Почему main () не может быть объявлен как static в C? - PullRequest
9 голосов
/ 26 ноября 2008

Почему main должен быть объявлен так, как будто он имеет внешнюю связь?

Почему оно не должно быть статичным?

что подразумевается под внешней связью ??

Ответы [ 2 ]

28 голосов
/ 26 ноября 2008

Потому что вы связываете файлы запуска с вашей программой, которая содержит (как правило) код ассемблера, который вызывает ваш 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
9 голосов
/ 26 ноября 2008

Реальная отправная точка кода похоронена в библиотеке времени выполнения C. Эта библиотека времени выполнения вызывает вашу подпрограмму main (). Чтобы компоновщик мог соединить вызов C RTL с вашей функцией main (), он должен быть виден вне файла.

Внешняя связь - это просто: это означает, что рассматриваемое имя отображается как часть экспорта объектного файла. Задача компоновщика - объединить все операции импорта и экспорта, чтобы не было невыполненных импортов.

...