Все разделы
Выбрать школу

Школа. Увлечения. Большое будущее.

PROSCHOOLS · ОБРАЗОВАНИЕ РЯДОМ

Ваш город

Выберите город, чтобы находить образование и возможности рядом.

Как учитываем городКаталог и кнопки «Выбрать школу» покажут школы выбранного города.Онлайн-курсы, учебник, ГДЗ и задания к экзаменам доступны по всей России.

Популярные города

Будет выбран: Вся Россия

Учебные материалы останутся прежними.

Поиск по сайту

По всему сайтуШколы выбранного города — выше в результатах

С чего начнём?

↑ ↓ — выбрать результат · Enter — открыть · Esc — закрыть

Extern в C: объявление переменной в нескольких файлах

💻 Информатика · 10 класс

Как разделить объявление и определение, собрать два файла и избежать ошибок компоновки.

Клавиатура в компьютерном классе
Иллюстрация к предмету «Информатика»Hmartil · Wikimedia Commons · CC BY-SA 4.0

Объявление не равно выделению памяти

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

Запись extern int score; без инициализатора сама по себе не создаёт новую отдельную переменную в каждом подключившем заголовок файле. Она сообщает, что существует объект соответствующего типа, с которым нужно связать обращения. Пример ниже использует язык C и внешнее связывание.

Три небольших файла

Файл score.h содержит общее объявление. Защита от повторного включения не заменяет extern: эти механизмы решают разные задачи.

#ifndef SCORE_H
#define SCORE_H
extern int score;
void add_point(void);
#endif

В score.c находится единственное определение и функция изменения:

#include "score.h"
int score = 0;
void add_point(void)
{
    ++score;
}

В main.c подключается то же объявление:

#include <stdio.h>
#include "score.h"
int main(void)
{
    add_point();
    printf("%d\n", score);
    return 0;
}

Команда cc -std=c17 main.c score.c -o demo компилирует оба исходных файла и связывает их в программу. При запуске программа выводит 1: функция меняет тот же объект, который затем читает main.

Как возникают ошибки

Если забыть score.c при сборке, объявление всё ещё позволит скомпилировать обращение, но на этапе компоновки определения не найдутся. Если поместить int score = 0; в общий заголовок, каждый включивший его файл может получить отдельное внешнее определение, что нарушает требование единственности определения объекта.

Инициализатор меняет смысл: extern int score = 0; на уровне файла является определением, несмотря на extern. Поэтому правило «extern всегда только объявляет» слишком категорично. Не используйте такую запись в общем заголовке для создания одной разделяемой переменной.

Связывание и область видимости

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

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

Практика

  1. Что выведет программа после двух вызовов add_point?
  2. Создаёт ли extern int score; новое значение 0?
  3. Почему одной main.c недостаточно для сборки примера?

Ответы

1. 2: оба вызова увеличивают общий объект. 2. Нет: это объявление без инициализатора, не отдельная инициализация. 3. В score.c находятся определения score и add_point. Заголовок сообщает интерфейс, но не подменяет код и данные модуля.

Связанные материалы

Источники и материалы