Как правильно использовать ключевое слово extern в C

Мой вопрос в том, когда функция должна ссылаться на ключевое слово extern в C.

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

Я мог подумать о том, как extern работает некорректно, и если так, пожалуйста, поправьте меня.

Изменить. Должно ли вы что-то extern когда это объявление по умолчанию без ключевого слова в файле заголовка?

« extern » изменяет связь. С ключевым словом предполагается, что функция / переменная доступна где-то в другом месте, и разрешение отложено на компоновщик.

Существует разница между «extern» на функциях и на переменных: по переменным он не создает экземпляр самой переменной, то есть не выделяет никакой памяти. Это нужно сделать где-то еще. Таким образом, важно, если вы хотите импортировать переменную из другого места. Для функций это говорит только компилятору, что ссылка является extern. Поскольку это значение по умолчанию (вы используете ключевое слово «static», чтобы указать, что функция не связана с использованием extern linkage), вам не нужно явно ее использовать.

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

С помощью ответов здесь и беседы с несколькими друзьями здесь приведен практический пример использования extern .

Пример 1 – показать ловушку:

 File stdio.h: int errno; /* other stuff...*/ 

 myCFile1.c: #include  Code... 

 myCFile2.c: #include  Code... 

Если myCFile1.o и myCFile2.o связаны, каждый из файлов c имеет отдельные копии errno . Это проблема, поскольку одна и та же ошибка должна быть доступна во всех связанных файлах.

Пример 2. Исправление.

 File stdio.h: extern int errno; /* other stuff...*/ 

 File stdio.c int errno; 

 myCFile1.c: #include  Code... 

 myCFile2.c: #include  Code... 

Теперь, если оба myCFile1.o и MyCFile2.o связаны линкером, они оба указывают на одно и то же errno . Таким образом, решая реализацию с помощью extern .

Уже было сказано, что ключевое слово extern избыточно для функций.

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

В C термин «extern» подразумевается для прототипов функций, поскольку прототип объявляет функцию, которая определена где-то еще. Другими словами, прототип функции имеет внешнюю связь по умолчанию; использование «extern» в порядке, но избыточно.

(Если требуется статическая привязка, функция должна быть объявлена ​​как «статическая» как в ее прототипе, так и в заголовке функции, и они обычно должны быть в одном файле .c).

Много лет спустя я открываю этот вопрос. Прочитав все ответы и комментарии, я мог бы прояснить несколько деталей … Это может быть полезно для людей, которые попадают сюда через поиск очков.

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

Давайте определим 3 прототипа функций

 //-------------------------------------- //Filename: "my_project.H" extern int function_1(void); static int function_2(void); int function_3(void); 

Файл заголовка может использоваться основным исходным кодом, как следует

 //-------------------------------------- //Filename: "my_project.C" #include "my_project.H" void main(void){ int v1 = function_1(); int v2 = function_2(); int v3 = function_3(); } int function_2(void) return 1234; 

Чтобы компилировать и связывать, мы должны определить «function_2» в том же файле исходного кода, где мы вызываем эту функцию. Две другие функции могут быть определены в другом исходном коде « .C» или они могут быть расположены в любом двоичном файле ( .OBJ, * .LIB, * .DLL), для которого у нас может не быть исходного кода.

Давайте снова включим заголовок «my_project.H» в другой файл «* .C», чтобы лучше понять разницу. В том же проекте мы добавим следующий файл // ————————————–

 //Filename: "my_big_project_splitted.C" #include "my_project.H" void old_main_test(void){ int v1 = function_1(); int v2 = function_2(); int v3 = function_3(); } int function_2(void) return 5678; int function_1(void) return 12; int function_3(void) return 34; 

Важные функции: Когда функция определяется как «статическая» в файле заголовка, компилятор / компоновщик должен найти экземпляр функции с этим именем в каждом модуле, который использует этот файл include.

Функция, которая является частью библиотеки C, может быть заменена только одним модулем, переопределяя прототип со «статикой» только в этом модуле. Например, замените любой вызов «malloc» и «free», чтобы добавить функцию обнаружения утечки памяти.

Спецификатор «extern» на самом деле не нужен для функций. Когда «статический» не найден, функция всегда считается «extern».

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

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

Очень хорошая статья о том, что я получил ключевое слово extern , а также примеры: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

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

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

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

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

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

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


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

Когда у вас есть эта функция, определенная в другой dll или lib, чтобы компилятор отследил компоновщика, чтобы найти его. Типичный случай – когда вы вызываете функции из OS API.

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

В большинстве случаев ваши функции будут одним из следующих (больше похоже на лучшую практику):

  • static (обычные функции, которые не видны вне этого файла .c)
  • static inline (встроенные в .c или .h файлы)
  • extern (объявление в заголовках следующего типа (см. ниже))
  • [без какого-либо ключевого слова] (обычные функции, предназначенные для доступа с использованием объявлений extern)
  • Gcc автоматически инициализирует статические переменные до нуля?
  • Использовать C ++ с Cocoa вместо Objective-C?
  • Передача многомерных массивов в качестве аргументов функции в C
  • Почему мы не можем использовать двойной указатель для представления двухмерных массивов?
  • Побитовая функция поворота влево
  • Использование транзакций или SaveChanges (false) и AcceptAllChanges ()?
  • Как работает getchar ()?
  • Возвращает `struct` из функции в C
  • Загадка (в C)
  • Почему FILE * не сохраняет адрес открытого файла
  • Как установить условную точку останова в Xcode на основе свойства объекта?
  • Давайте будем гением компьютера.