Как использовать extern для обмена переменными между исходными файлами?
Я знаю, что глобальные переменные в C иногда имеют ключевое слово extern
. Что такое переменная extern
? Каково её объявление? Каков её диапазон видимости?
Это связано с обменом переменными между исходными файлами, но как именно это работает? Где мне использовать extern
?
5 ответ(ов)
Переменная с ключевым словом extern
является декларацией (спасибо sbi за исправление) переменной, которая определена в другом объектном файле. Это означает, что память для этой переменной выделяется в другом файле.
Предположим, у вас есть два файла .c
: test1.c
и test2.c
. Если вы определяете глобальную переменную int test1_var;
в test1.c
и хотите получить доступ к этой переменной в test2.c
, вам нужно использовать extern int test1_var;
в test2.c
.
Вот полный пример:
// test1.c
int test1_var = 5;
// test2.c
#include <stdio.h>
extern int test1_var;
int main(void) {
printf("test1_var = %d\n", test1_var);
return 0;
}
Компилируйте оба файла и запускайте:
$ gcc test1.c test2.c -o test
$ ./test
test1_var = 5
Таким образом, используя extern
, вы можете ссылаться на переменные, определенные в других файлах, что позволяет организовать код более гибко и избегать дублирования.
Ключевое слово extern
используется для того, чтобы объявить, что переменная находится в другом объектном модуле (translation unit).
Это позволяет вам использовать переменную в одном объектном модуле и затем обращаться к ней из другого. В этом случае, во втором модуле вы объявляете переменную как extern
, и значение будет разрешено компоновщиком (linker).
Если вы не объявите переменную как extern
, у вас получится две переменные с одинаковыми именами, которые не будут связаны, что приведет к ошибке множественного определения переменной.
В вашем вопросе рассматриваются различия между декларацией, определением и инициализацией переменных в C/C++. Давайте разберем ваш пример.
declare | define | initialize |
----------------------------------
extern int a; yes no no
-------------
int a = 2019; yes yes yes
-------------
int a; yes yes no
-------------
Разбор таблицы:
extern int a;
- Декларация: Да
- Определение: Нет
- Инициализация: Нет
В этом случае происходит лишь объявление переменнойa
, которая будет определена где-то еще (например, в другом файле). Память для переменнойa
не выделяется.
int a = 2019;
- Декларация: Да
- Определение: Да
- Инициализация: Да
Здесь происходит как объявление переменной, так и выделение для неё памяти (определение). Переменнойa
присваивается значение 2019, что также является инициализацией.
int a;
- Декларация: Да
- Определение: Да
- Инициализация: Нет
В этом случае переменнаяa
объявляется и определяется, но ей не присваивается никакое значение (инициализация не производится). Память для неё выделяется, но её значение остается неопределённым.
Общий вывод: Декларация переменной не приводит к выделению памяти, пока переменная не будет определена. Определение же, как правило, ведёт к выделению памяти. Такой подход позволяет четко различать эти понятия, что очень важно при работе с переменными и ключевым словом extern
.
Я люблю думать о переменной extern
как о обещании, которое вы даете компилятору.
Когда компилятор встречает extern
, он может определить только её тип, но не знает, где она "находится", поэтому не может разрешить это обращение.
Вы как бы говорите компилятору: "Доверься мне. Во время линковки это обращение будет разрешено."
extern
говорит компилятору, что память для этой переменной объявлена где-то еще, поэтому он не будет пытаться выделять или проверять память.
Таким образом, вы можете скомпилировать файл, который ссылается на extern
, но не сможете сделать линковку, если эта память не объявлена где-либо.
Это полезно для глобальных переменных и библиотек, но может быть опасно, так как линковщик не проводит проверку типов.
В чем разница между #include <filename> и #include "filename"?
Как изменить цвет вывода echo в Linux
Каково влияние extern "C" в C++?
Разница между const int*, const int * const и int * const?
Является ли < быстрее, чем <=?