Мой вопрос о том, когда на функцию следует ссылаться с extern
ключевым словом в C.
Я не понимаю, когда это следует использовать на практике. Поскольку я пишу программу, все функции, которые я использую, становятся доступными через файлы заголовков, которые я включил. Так почему было бы полезно extern
получить доступ к тому, что не было представлено в заголовочном файле?
Я мог бы думать о том, как extern
работает неправильно, и если так, пожалуйста, поправьте меня.
Изменить: Должны ли вы extern
что-то, когда это объявление по умолчанию без ключевого слова в заголовочном файле?
Ответы:
«
extern
» меняет связь. С ключевым словом предполагается, что функция / переменная доступна где-то еще, а разрешение откладывается до компоновщика.Существует разница между «extern» в функциях и в переменных: для переменных она не создает экземпляр самой переменной, то есть не выделяет никакой памяти. Это должно быть сделано где-то еще. Поэтому важно, если вы хотите импортировать переменную из другого места. Для функций это только говорит компилятору, что связь внешняя. Поскольку это значение по умолчанию (вы используете ключевое слово «static», чтобы указать, что функция не связана с использованием внешней связи), вам не нужно использовать это явно.
источник
extern сообщает компилятору, что эти данные где-то определены и будут связаны с компоновщиком.
С помощью ответов здесь и общения с несколькими друзьями здесь приведен практический пример использования extern .
Пример 1 - показать подводный камень:
Если myCFile1.o и myCFile2.o связаны между собой, каждый из c-файлов имеет отдельные копии errno . Это проблема , как же ERRNO должна быть доступна во всех связанных файлов.
Пример 2 - Исправление.
Теперь, если и myCFile1.o, и MyCFile2.o связаны компоновщиком, они оба будут указывать на одну и ту же ошибку . Таким образом, решаем реализацию с помощью extern .
источник
-Wall
и-pedantic
. Зачем ? и как ?Уже было сказано, что
extern
ключевое слово является избыточным для функций.Что касается переменных, совместно используемых в единицах компиляции, вы должны объявить их в заголовочном файле с ключевым словом extern, а затем определить их в одном исходном файле без ключевого слова extern. Для лучшей практики единственным исходным файлом должен быть файл с общим именем файла заголовка.
источник
Спустя много лет я обнаруживаю этот вопрос. Прочитав каждый ответ и комментарий, я подумал, что смогу уточнить некоторые детали ... Это может быть полезно для людей, которые попадают сюда через поиск в Google.
Речь идет конкретно об использовании «внешних» функций, поэтому я буду игнорировать использование «внешних» с глобальными переменными.
Давайте определим 3 прототипа функции:
Заголовочный файл может использоваться основным исходным кодом следующим образом:
Чтобы скомпилировать и связать, мы должны определить «function_2» в том же файле исходного кода, где мы вызываем эту функцию. Две другие функции могут быть определены в другом исходном коде " .C" или они могут находиться в любом двоичном файле ( .OBJ, * .LIB, * .DLL), для которого у нас может не быть исходного кода.
Давайте снова включим заголовок «my_project.H» в другой файл «* .C», чтобы лучше понять разницу. В том же проекте мы добавляем следующий файл:
Важные особенности, на которые следует обратить внимание:
Когда функция определена как «статическая» в заголовочном файле, компилятор / компоновщик должен найти экземпляр функции с таким именем в каждом модуле, который использует этот включаемый файл.
Функция, которая является частью библиотеки C, может быть заменена только в одном модуле путем переопределения прототипа на «static» только в этом модуле. Например, замените любой вызов «malloc» и «free», чтобы добавить функцию обнаружения утечки памяти.
Спецификатор "extern" на самом деле не нужен для функций. Когда «статический» не найден, функция всегда считается «внешней».
Однако «extern» не является значением по умолчанию для переменных. Обычно любой заголовочный файл, который определяет переменные, которые должны быть видны во многих модулях, должен использовать «extern». Единственное исключение будет, если заголовочный файл гарантированно будет включен из одного и только одного модуля.
Многие менеджеры проектов тогда требуют, чтобы такая переменная была помещена в начале модуля, а не внутри какого-либо заголовочного файла. Некоторые крупные проекты, такие как эмулятор видеоигры «Mame», даже требуют, чтобы такая переменная появлялась только над первой функцией, использующей их.
источник
В C 'extern' подразумевается для прототипов функций, поскольку прототип объявляет функцию, которая определена где-то еще. Другими словами, у прототипа функции есть внешняя связь по умолчанию; использование 'extern' хорошо, но излишне.
(Если требуется статическая связь, функция должна быть объявлена как «статическая» как в ее прототипе, так и в заголовке функции, и они обычно должны быть в одном и том же файле .c).
источник
Очень хорошая статья о
extern
ключевом слове и примеры: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/Хотя я не согласен, что использование
extern
в объявлениях функций является излишним. Предполагается, что это настройка компилятора. Поэтому я рекомендую использоватьextern
в объявлениях функций, когда это необходимо.источник
Если каждый файл в вашей программе сначала компилируется в объектный файл, тогда объектные файлы связаны вместе, вам нужно
extern
. Он сообщает компилятору: «Эта функция существует, но код для нее находится где-то еще. Не паникуйте».источник
Все объявления функций и переменных в заголовочных файлах должны быть
extern
.Исключением из этого правила являются встроенные функции, определенные в заголовке, и переменные, которые - хотя и определены в заголовке - должны быть локальными для модуля перевода (исходный файл, в который включается заголовок): они должны быть
static
.В исходных файлах
extern
не должен использоваться для функций и переменных, определенных в файле. Просто добавьте локальные определения кstatic
и ничего не делайте для общих определений - по умолчанию они будут внешними символами.Единственная причина для использования
extern
вообще в исходном файле - это объявление функций и переменных, которые определены в других исходных файлах и для которых не предусмотрен файл заголовка.Объявление прототипов функций на
extern
самом деле не нужно. Некоторым людям это не нравится, потому что оно будет просто тратить пространство, а объявления функций уже имеют тенденцию переполнять ограничения строк. Другим это нравится, потому что таким образом функции и переменные могут обрабатываться одинаково.источник
extern
является необязательным для объявлений функций, но мне нравится обрабатывать переменные и функции одинаково - по крайней мере, это наиболее разумная вещь, которую я могу придумать, поскольку я точно не помню, почему я начал это делать;)Функции, фактически определенные в других исходных файлах, должны быть объявлены только в заголовках. В этом случае вы должны использовать extern при объявлении прототипа в заголовке.
В большинстве случаев ваши функции будут одним из следующих (больше похоже на передовой опыт):
источник
Когда эта функция определена в другой dll или lib, так что компилятор обращается к компоновщику, чтобы найти ее. Типичный случай, когда вы вызываете функции из OS API.
источник