Урок 49. Глобальные переменные

   ⁄ 

 Обновлено 1 Апр 2017

  ⁄   

Мы уже знаем, что переменные, объявленные внутри блока, называются локальными. Они имеют локальную область видимости (видны только внутри блока, в котором объявлены) и автоматическую продолжительность (создаются в точке определения и уничтожаются в конце блока).

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

Определение глобальных переменных

Обычно глобальные переменные объявляют в верхней части кода, ниже директив #include, но выше любого другого кода. Например:

Подобно тому, как переменные во внутреннем блоке скрывают переменные с теми же именами во внешнем блоке, локальные переменные скрывают глобальные переменные с одинаковыми именами внутри блока, в котором они определены. Однако с помощью оператора глобальной области видимости (::) компилятору можно сообщить, какую версию переменной вы имеете в виду: глобальную или локальную.

Результат:

global value: 3
local value: 9

Использовать одинаковые имена для локальных и глобальных переменных – это прямой путь к проблемам и ошибкам, поэтому подобное следует избегать. Еще многие разработчики добавляют к глобальным переменным префикс g_ (“g” = “global”). Таким образом можно убить сразу двух зайцев: определить глобальные переменные и избежать конфликтов имен с локальными переменными.

Внутренняя и внешняя связь через ключевые слова static и extern

В дополнение к области видимости и продолжительности, переменные имеют еще одно свойство: связь (linkage). Связь переменной определяет, относятся ли несколько упоминаний одного идентификатора к одной и той же переменной или нет.

Переменная без связей – эта переменная с локальною областью видимости, которая относится только к блоку в котором определена. Это обычные локальные переменные. Две переменные с одинаковыми именами, но определенные в разных функциях, не имеют никакой связи – каждая считается независимой единицей.

Переменная, имеющая внутренние связи, называется внутренней переменной (или статической). Она может использоваться в любом месте файла, в котором определена, но не относиться к чему-либо вне этого файла.

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

Если вы хотите сделать глобальную переменную внутренней (которую можно использовать только внутри одного файла) – используйте ключевое слово static:

Аналогично, если вы хотите сделать глобальную переменную внешней (которую можно использовать в любом файле программы) – используйте ключевое слово extern:

По умолчанию, неконстантные переменные, объявленные вне блока, считаются внешними. Однако константные переменные, объявленные вне блока, считаются внутренними.

Предварительные объявления переменных через ключевое слово extern

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

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

Например:

global.cpp:

main.cpp:

Если предварительное объявление находится вне блока, то оно применяется ко всему файлу. Если же внутри блока, то применяется только к нему.

Если переменная объявлена как static, то получить доступ к ней с помощью предварительного объявления не получится:

constants.cpp:

main.cpp:

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

Связи функций

Функции имеют такие же свойства связи, что и переменные. По умолчанию они внешние, но можно сменить на внутренние с помощью ключевого слова static:

Предварительные объявления функций не нуждаются в ключевом слове extern. Компилятор может установить сам, определяете ли вы функцию или пишите прототип, по телу функции: есть оно или нет.

Файловая область видимости vs глобальная область видимости

Термины “файловая область видимости” и “глобальная  область видимости”, как правило, вызывают недоумение, и это отчасти объясняется их неофициальным использованием. Технически, в C++ все глобальные переменные имеют файловую область видимости. Однако, неофициально, термин “файловая область видимости” чаще применяется к внутренним глобальным переменным, а “глобальная область видимости” к внешним глобальным переменным.

Рассмотрим следующую программу:

global.cpp:

main.cpp:

g_y имеет файловую область видимости внутри global.cpp – доступа к нему вне этого файла нет. Обратите внимание, хоть эта переменная используется в main.cpp, main.cpp не видит её, он видит только предварительное объявление g_y (которое также имеет файловую область видимости). Линкер отвечает за связь определения g_y в global.cpp с использованием g_y в main.cpp.

Глобальные символьные константы

В уроке о символьных константах, мы определили их как:

constants.h:

Хоть это просто и отлично подходит для небольших программ, но каждый раз, когда constants.h подключается в другой файл — каждая из этих переменных копируется в этот файл. Таким образом, если constants.h подключить в 20 различных файлов, то каждая из переменных продублируется 20 раз. Header guards не остановят это, так как они только предотвращают подключение заголовочного файла более одного раза в один файл. Дублирование переменных на самом деле не является проблемой (поскольку константы в основном не занимают много памяти), но изменение одного значения константы потребует перекомпиляции каждого файла, в котором они подключены, что может привести к большим затратам времени на восстановление в более крупных проектах.

Избежать этой проблемы можно, превратив эти константы в константные глобальные переменные, и изменив заголовочный файл только для хранения предварительных объявлений переменных:

constants.cpp:

constants.h:

Их использование в коде остается неизменным:

Теперь определение символьных констант будет только один раз (в constants.cpp). Любые изменения, сделанные в constants.cpp, потребуют перекомпиляции только одного этого файла.

Но есть и обратная сторона медали: такие константы больше не будут считаться константами типа compile-time и поэтому не смогут использоваться где-либо, где потребуется константа такого типа.

Поскольку глобальные символьные константы должны находиться в пространстве имен (namespace) и быть доступными только для чтения, то использовать префикс g_ уже не обязательно.

Предостережение о (неконстантных) глобальных переменных

В начинающих программистов часто возникает соблазн использовать просто множество глобальных переменных, поскольку с ними легко работать, особенно когда задействовано много функций. Тем не менее, этого следует избегать! Почему? Об этом поговорим в следующем уроке.

Итого

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

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

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

Используйте префикс g_ для идентификации ваших неконстантных глобальных переменных.

Ниже мы навели примеры использования ключевых слов extern и static с неконстантными и константными переменными:

Тест

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

Ответ

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

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

Глобальные переменные имеют статическую продолжительность, что означает, что они создаются при запуске программы и уничтожаются, когда она заканчивается.

Глобальные переменные могут иметь либо внутреннюю, либо внешнюю связь, через ключевые слова static и extern соответственно.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (10 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *