Является ли ключевое слово extern для функции, необходимой вообще в C?
Мне кажется, что даже если я ссылаюсь на функцию в другом файле с объявлением extern, gcc все еще может скомпилировать этот блок. Поэтому мне интересно, нужна ли декларация extern для работы? Я знаю, что вам нужны внешние переменные.
Ответы
Ответ 1
функции имеют спецификатор класса extern storage по умолчанию (если они явно не определены как статические)
extern Storage Class Specifier
Если декларация описывает функцию или появляется за пределами функции и описывает объект с внешней связью, ключевое слово extern необязательно. Если вы не укажете спецификатор класса хранения, предполагается, что функция имеет внешнюю связь.
....
Ошибка включения декларации для той же функции со спецификатором класса хранения static перед объявлением без спецификации класса хранения из-за несовместимых объявлений. Включение спецификатора класса extern storage в исходное объявление является допустимым, а функция имеет внутреннюю привязку.
Ответ 2
Это не нужно, но я предпочитаю в заголовках укрепить идею о том, что эта функция определена где-то еще.
Для меня это:
int func(int i);
является прямым объявлением функции, которая понадобится позже, а это:
extern int func(int i);
является объявлением функции, которая будет использоваться здесь, но определена в другом месте.
Две строки функционально идентичны, но я использую ключевое слово extern
для документирования разницы и для согласованности с регулярными переменными (где разница важна и имеет именно это значение).
Ответ 3
Для переменных необязательно extern.
Когда C было изобретено, были также написаны Unix-линкеры, и они продвигали искусство незамысловатыми, но умными способами. Одним из вкладов было определение всех символов как небольших "общих блоков". Это позволило использовать один синтаксис для объявлений без требуемой спецификации того, какой модуль выделял пространство. (Только один модуль мог фактически инициализировать объект, но никто не требовался.)
Есть три соображения.
-
Передовые декларации для прототипов. (Необязательно, потому что устаревшее C должно компилироваться без них.)
-
Заявления extern для не-функциональных объектов (переменных) во всех файлах, кроме одного. (Требуется только для не-Unix-систем, у которых также есть crummy-линкеры. Надеюсь, это редкость в наши дни.)
-
Для функций extern уже является предположением, если тело функции не существует, чтобы сформировать определение.
Ответ 4
Насколько я помню стандарт, все объявления функций считаются "extern" по умолчанию, поэтому нет необходимости явно указывать его.
Это не делает это ключевое слово бесполезным, так как оно также может использоваться с переменными (и в этом случае - это единственное решение для решения проблем связи). Но с функциями - да, это необязательный.
Несколько более подробный ответ заключается в том, что он позволяет использовать переменные, скомпилированные в другом файле исходного кода, но не резервирует память для переменной. Таким образом, чтобы использовать extern, вы должны иметь файл исходного кода или библиотечный модуль, который содержит пространство памяти для переменной на верхнем уровне (не внутри функций). Теперь вы можете обратиться к этой переменной, указав внешнюю переменную с тем же именем в других файлах исходного кода.
В общем случае следует избегать использования определения extern. Они легко приводят к неуправляемому коду и ошибкам, которые трудно найти. Конечно, есть примеры, когда другие решения были бы непрактичными, но они редки. Например, stdin и stdout являются макросами, которые сопоставляются с переменной внешнего элемента типа FILE * в stdin.h; пространство памяти для этого массива находится в стандартном блоке C-библиотеки.