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

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

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

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

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

Ответ 1

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

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

Ответ 2

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

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

Пример 1 -, чтобы показать ловушку:

File stdio.h:

int errno;
/* other stuff...*/

myCFile1.c:
#include <stdio.h>

Code...

myCFile2.c:
#include <stdio.h>

Code...

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

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

File stdio.h:

extern int errno;
/* other stuff...*/

File stdio.c

int errno;

myCFile1.c:
#include <stdio.h>

Code...

myCFile2.c:
#include <stdio.h>

Code...

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

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

Давайте определим 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;

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

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

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

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


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

Ответ 9

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

Ответ 10

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

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

  • static (обычные функции, которые не являются видимый вне этого .c файла)
  • статический встроенный (inlines from.c или .h файлы)
  • extern (объявление в заголовках следующий вид (см. ниже))
  • [без ключевого слова вообще] (нормальный функции, предназначенные для доступа, используя объявления extern)

Ответ 11

Экстерн: "ключевое слово extern по умолчанию представляет перед любым объявлением переменной.Компилятор скрывает его.Когда вы хотите объявить функцию и она определена где-то в файле проекта, в таких условиях extern играет хорошую роль. Например, просто рассмотрите сокет программы, вы используете #include.Если вы пользователь Linux, найдите файл socket.h в своем компьютере и откройте его. Вы можете использовать множество объявлений функций extern. Это означает, что ваш заголовок" socket.h" объявлен всем требуемые функции, которые будут загружаться при запуске компиляции.Эти функции extern определены где-то в двоичных файлах сокетов.Еще нужно просто включить заголовочный файл. Ответственность линкера за загрузку двоичного файла для выполнения.

Все вышеприведенные примеры рассказывают об использовании, я просто перешел на уровень ОС.