Требуется ли ключевое слово extern для функции вообще в C? - PullRequest
16 голосов
/ 10 марта 2011

Мне кажется, что даже если я ссылаюсь на функцию в другом файле без объявления extern, gcc все равно может скомпилировать этот модуль.Поэтому мне интересно, нужно ли где-нибудь объявление extern для функции?Я знаю, что вам нужен extern для переменных.

Ответы [ 4 ]

12 голосов
/ 10 марта 2011

В этом нет необходимости, но я предпочитаю, чтобы в заголовках он подкреплял идею, что эта функция определена где-то еще.

Для меня это:

int func(int i);

- это предварительное объявление функции, которая понадобится позже, тогда как:

extern int func(int i);

- это объявление функции, которая будет использоваться здесь, но определена в другом месте.

Эти две строки функционально идентичны, но я использую ключевое слово extern для документирования различия и для согласованности с обычными переменными (где разница важна и имеет именно это значение).

12 голосов
/ 10 марта 2011

функции имеют спецификатор класса внешнего хранилища по умолчанию (если они явно не определены как статические)

внешний спецификатор класса хранения

Если объявление описывает функцию или появляется вне функции и описывает объект с внешней связью, ключевое слово extern необязательно . Если вы не укажете спецификатор класса хранения, предполагается, что функция имеет внешнюю связь.

....

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

6 голосов
/ 10 марта 2011

Вы делаете , а не обязательно " нужно " extern для переменных.

Когда C был изобретен, Unix были также написаны линкеры, и онипродвигал искусство необузданными, но умными способами.Один вклад определял все символы как маленькие «общие блоки».Это позволило использовать единый синтаксис для объявлений без обязательной спецификации того, какой модуль выделял пространство.(Только один модуль мог на самом деле инициализировать объект, но это никому не требовалось.)

На самом деле есть три соображения.

  1. Пересылка объявлений для прототипов.(Необязательно, потому что устаревший C должен компилироваться без них.)

  2. Внешние объявления для нефункциональных объектов (переменных) во всех файлах, кроме одного.(Требуется только в не-Unix системах, в которых также есть непристойные линкеры. Надеюсь, в наши дни это случается редко.)

  3. Для функций extern уже является предположением, если тело функции не присутствует для формированияопределение.

2 голосов
/ 15 мая 2017

Насколько я помню стандарт, все объявления функций по умолчанию считаются "extern" , поэтому нет необходимости указывать его явно. Это не делает это ключевое слово бесполезным, поскольку его также можно использовать с переменными (и в этом случае - это единственное решение для решения проблем с сцеплением). Но с функциями - да, это необязательно .

Немного более подробный ответ заключается в том, что он позволяет вам использовать переменные, скомпилированные в другом файле исходного кода, но не резервирует память для этой переменной. Таким образом, чтобы использовать extern, вы должны иметь файл исходного кода или библиотечный модуль, который содержит пространство памяти для переменной верхнего уровня (не внутри функций). Теперь вы можете обратиться к этой переменной, определив переменную extern с тем же именем в других файлах исходного кода.

В целом, следует избегать использования внешнего определения. Они легко приводят к неуправляемому коду и ошибкам, которые трудно обнаружить. Конечно, есть примеры, когда другие решения были бы непрактичными, но они редки. Например, stdin и stdout - это макросы, которые отображаются в переменную внешнего массива типа FILE * в stdin.h; пространство памяти для этого массива находится в стандартном модуле C-библиотеки.

...