TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.36K subscribers
Post #1050 4.1K
​​Объявления функций vs объявление переменной или зачем нужен extern
#новичкам

В С/С++ существует интересная механика - разделение на объявление сущности и ее определение. У этого есть серьезные причины:

👉🏿 Ускорение компиляции: изменения в реализации не требуют перекомпиляции всех файлов, использующих объявление.

👉🏿 Сокрытие реализации: инкапсуляция, предоставление только интерфейса (в .hpp) и скрытие деталей в .cpp.

👉🏿 Разрешение циклических зависимостей и возможность ссылаться на типы до их полного определения.

👉🏿 Организация кода и разделение ответственности.

И если с функциями более менее понятно. Есть объявление в виде обозначения сигнатуры функции. И определение в виде полного предоставления тела функции:

void foo(int a); // declaration

void foo(int a) {
std::cout << a << std::endl; // definition
}


С переменными все немного сложнее. Но начнем с легкого:

int i = 0;


Это определение хоть глобальной, хоть локальной переменной i и ее инициализация нулем. Все все понимают.

Если думать в аналогии с функциями, то легко дойти до мысли что:

int i;


это объявление переменной.

Но это не так!

Это в любом случае определение!

Если вы встретите такую строчку вне функции, то это определение переменной и ее инициализация нулем. А внутри функции - определение без инициализации(значение будет мусорное). Определение переменной всегда связано с созданием объекта и выделением памяти под него.

Тогда как сказать компилятору, что я буду использовать переменную с каким-то именем и типом, но не хочу создавать объект а буду сслаться на определение в другом месте?

Ровно для этого и нужно ключевое слово extern.

extern int i; // declaration

int main() {
std::cout << i << std::endl;
}

int i = 42;

// OUTPUT
// 42


До мейна мы сказали, что будем ссылаться на переменную i, определение которой лежит в другом месте. И сразу после мейна предоставляем это определение. Компилятор все понял и в итоге мы получаем 42 на консоли, а не ноль.

В этом случае строчка extern int i; является объявлением глобальной переменной i.

Определение переменной может находиться хоть в другой единице трансляции. Просто тогда зависимости будут разрешаться на этапе линковки.

Для локальных переменных функций объявление не предусмотрено(оно и не нужно). Если попытаетесь сделать так:

int main() {
extern int i;
std::cout << i << std::endl;
}


То вы опять объявите глобальную переменную i.

То есть чисто объявить вы можете только глобальную переменную (про полям класса речь не идет) и только с помощью extern.

Declare your intentions. Stay cool.

#cppcore
  • 🔥 21
  • 👍 11
  • ❤ 9
  • 🤣 3
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →