где будет определена объявленная переменная extern?

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

//globalheader.h//

extern int test_var;

//file1.c//
#include "globalheader.h"

static fn1();
fn1
{
   int a;
   a = test_var;
}

//file2.c//
#include "globalheader.h"

static fn2();
fn2
{
   int b = 1;
   test_var = b;
}

В приведенном выше фрагменте кода test_var объявлен с внешней ссылкой в ​​файле globalheader.h, который был включен как в файл1.c, так и в файл2.c. Нет, где эта test_var была определена, но использовалась, так где (в каком объектном файле) эта test_var будет выделена память?


person Opener    schedule 06.12.2013    source источник
comment
В исходном файле, который его определяет, могут отсутствовать некоторые файлы.   -  person moeCake    schedule 06.12.2013
comment
Он нигде не определяется автоматически, в то время как верно обратное: определение также объявляет элемент (и в большинстве случаев определение не должно конфликтовать с более ранним объявлением)   -  person Aki Suihkonen    schedule 06.12.2013


Ответы (4)


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

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

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

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

person nos    schedule 06.12.2013

Ключевое слово «extern» только информирует компилятор о том, что место в памяти доступно для данной переменной, поэтому не выделяйте новую область памяти. Из-за этого, когда вы будете компилировать файлы file1.c и file2.c, соответствующий объектный код не будет содержать области памяти. Вы также можете заметить размер объектного файла. если вы объявили какую-либо переменную как extern, то размер объекта для этой переменной не будет увеличен, и как только вы удалите extern и перекомпилируете, размер объекта увеличится. Во время компоновки компоновщик будет искать объектный файл, в котором область памяти определена для этой переменной (которая определена как внешняя в других файлах) из заданных объектных файлов. Согласно вашему коду, вы нигде не определили переменную, поэтому область памяти для переменной test_var нигде не выделена, поэтому во время компоновки компоновщик выдаст ошибку «undefined reference test_var».

person rajenpandit    schedule 06.12.2013

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

person Rob    schedule 06.12.2013
comment
Нет. Он нигде не определен, только объявлен. Это не может возможно связать. - person ; 06.12.2013
comment
Это зависит от линкера. Я работал со старыми линкерами, которые это позволяют. Я изменил свой ответ. - person Rob; 06.12.2013

Когда вы объявляете переменную как extern, предполагается, что она существует в каком-то другом файле. В этом случае компоновщик выдаст ошибку, если это не так.

Однако в C есть исключение (которого не существует в C++). Если переменной также присвоено значение, она также будет объявлена.

Если вы пишете:

 extern int var;

и var не существует в каком-то другом модуле, это не удастся.

Если вы пишете:

 extern int var = 0;

и var не существует в каком-то другом модуле, он будет успешным.

Очевидно, что переменная будет находиться в файле, где она объявлена.

person Devolus    schedule 06.12.2013