что такое глобальные переменные

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

Обновл. 24 Сен 2021 |

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

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

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

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

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

Результат выполнения программы:

Global value: 3
Local value: 9

Ключевые слова static и extern

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

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

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

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

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

Источник

Что такое глобальные переменные

Как вы уже знаете, функции позволяют разделить программу на небольшие легко управляемые части. Все функции, используемые вами до настоящего момента, были совершенно просты. Как только вашим функциям потребуется выполнить более сложную работу, они должны будут использовать переменные для реализации своих задач. Переменные, объявляемые внутри функции, называются локальными переменными. Их значения и даже сам факт, что локальные переменные существуют, известны только данной функции, Другими словами, если вы объявляете локальную переменную с именем salary в функции payroll, то другие функции не имеют доступа к значению переменной salary. Фактически, другие функции не имеют никакого представления о том, что переменная salary существует. Этот урок рассматривает область видимости переменной, или участок внутри вашей программы, в котором переменная известна. К концу этого урока вы освоите следующие основные концепции:

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

• Имена переменных, используемых внутри функций, должны быть уникальными только по отношению к данной функции.

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

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

• Оператор глобальной области видимости C++ (::) позволяет вам управлять областью видимости переменной.

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

ОБЪЯВЛЕНИЕ ЛОКАЛЬНЫХ ПЕРЕМЕННЫХ

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

Следующая программа USEBEEPS.CPP использует функцию so und_speaker, которая заставляет играть встроенный компьютерный динамик столько раз, сколько указано параметром beeps. Внутри функции so und_speaker локальная переменная counter хранит количество звуков, издаваемых динамиком:

void sound_beeps(int beeps)

<
for (int counter = 1; counter

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

О конфликте имен

int add_values(int a, int b)
<
int value;
value =a + b;
return(value);
>

<
int value = 1001;
int other value = 2002;
cout » = «

О локальных переменных

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

ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

Как вы уже знаете, локальная переменная объявляется и известна только в определенной функции. В дополнение к локальным переменным C++ позволяет вашим программам объявлять глобальные переменные, которые известны на протяжении всей программы (глобально для всех функций). Чтобы объявить глобальную переменную, следует просто поместить объявление переменной в начало вашей программы вне какой-либо функции:

<
// Здесь должны быть операторы программы
>

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

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

Если имена глобальных и локальных переменных конфликтуют

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

Однако могут быть ситуации, когда вам необходимо обратиться к глобальной переменной, чье имя конфликтует с именем локальной переменной. В таких случаях ваши программы могут использовать глобальный оператор разрешения С++ (::), если вы хотите использовать глобальную переменную. Например, предположим, что у вас есть глобальная и локальная переменные с именем number. Если ваша функция хочет использовать локальную переменную number, она просто обращается к этой переменной, как показано ниже:

number = 1001; // обращение к локальной переменной

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

::number = 2002; // Обращение к глобальной переменной

Следующая программа GLOBLOCA.CPP использует глобальную переменную number. В дополнение к этому функция show_numbers использует локальную переменную с именем number. Эта функция использует оператор глобального разрешения для обращения к глобальной переменной:

#include int number = 1001; // Глобальная переменная

void show_numbers(int number)

void main(void)
<
int some_value = 2002;
show_numbers(some_value) ;
>

Когда вы откомпилируете и запустите эту программу, на вашем экране появится следующий вывод:

Локальная переменная number содержит 2002

Глобальная переменная number содержит 1001

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

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

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

Представление об области видимости переменных

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

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

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

Источник

6.4 – Введение в глобальные переменные

В уроке «6.3 – Локальные переменные» мы рассмотрели, что локальные переменные – это переменные, определенные внутри функции (или параметры функции). Локальные переменные имеют область видимости блока (видны только внутри блока, в котором они объявлены) и имеют автоматическую продолжительность (они создаются в точке определения и уничтожаются при выходе из блока).

В C++ переменные также могут быть объявлены вне функции. Такие переменные называются глобальными переменными.

Объявление и именование глобальных переменных

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

Приведенный выше пример напечатает:

По соглашению многие разработчики добавляют к идентификаторам глобальных переменных префикс » g » или » g_ «, чтобы указать, что они глобальные.

Лучшая практика

Рассмотрите возможность использования префикса » g » или » g_ » для глобальных переменных, чтобы помочь отличить их от локальных переменных.

Глобальные переменные имеют область видимости файла и статическую продолжительность

Поскольку они определяются вне функции, глобальные переменные считаются частью глобального пространства имен (отсюда и термин «область видимости глобального пространства имен»).

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

В отличие от локальных переменных, которые по умолчанию не инициализируются, статические переменные по умолчанию инициализируются нулем.

Инициализация глобальной переменной

При желании неконстантные глобальные переменные можно инициализировать:

Константные глобальные переменные

Как и локальные переменные, глобальные переменные могут быть константными. Как и все константы, константные глобальные переменные должны быть инициализированы.

Связанный контент

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

У начинающих программистов часто возникает соблазн использовать множество глобальных переменных, потому что их можно использовать без явной передачи их каждой функции, которая в них нуждается. Однако следует вообще избегать использования неконстантных глобальных переменных! А почему, мы обсудим в следующем уроке «6.9 – Почему глобальные переменные – это зло».

Источник

Руководство Google по стилю в C++. Часть 3

Часть 1. Вступление
Часть 2. Заголовочные файлы
Часть 3. Область видимости
Часть 4. Классы

что такое глобальные переменные. Смотреть фото что такое глобальные переменные. Смотреть картинку что такое глобальные переменные. Картинка про что такое глобальные переменные. Фото что такое глобальные переменные

Эта статья является переводом части руководства Google по стилю в C++ на русский язык.
Исходная статья (fork на github), обновляемый перевод.

Область видимости

Пространство имён

Размещайте свой код в пространстве имён (за некоторыми исключениями). Пространство имён должно иметь уникальное имя, формируемое на основе названия проекта, и, возможно, пути. Не используйте директиву using (например, using namespace foo). Не используйте встроенные (inline) пространства имён. Для безымянных пространств имён смотрите Безымянные пространства имён и статические переменные.

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

За
Пространства имён позволяют избежать конфликта имён в больших программах, при этом сами имена остаются достаточно короткими.
Например, если два разных проекта содержат класс Foo в глобальной области видимости, имена могут конфликтовать. Если каждый проект размещает код в своё пространство имён, то project1::Foo и project2::Foo будут разными именами, конфликтов не будет, в то же время код каждого проекта будет использовать Foo без префикса.
Пространства имён inline автоматически делают видимыми свои имена для включающего пространства имён. Рассмотрим пример кода:

Здесь выражения outer::inner::foo() и outer::foo() взаимозаменяемы. Inline пространства имён в основном используются для ABI-совместимости разных версий.

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

Заключайте в пространство имён целиком файл с исходным кодом после #include-ов, объявлений/определений gflag-ов и предварительных объявлений классов из других пространств имён.

В .cc файлах могут быть дополнительные объявления, такие как флаги или using-декларации.

Не используйте using-директиву чтобы сделать доступными все имена из пространства имён.

Не используйте псевдонимы пространств имён в блоке namespace в заголовочном файле, за исключением явно обозначенных «внутренних» пространств имён. Связано это с тем, что любая декларация в заголовочном файле становится частью публичного API, экспортируемого этим файлом.

Безымянные пространства имён и статические переменные

Когда определения внутри .cc файла не используются в других исходных файлах, размещайте такие определения в безымянном пространстве имён или объявляйте их как static. Не используйте такой тип определения в заголовочных файлах (.h).

Определение
Размещённые в безымянном пространстве имён объявления могут быть слинкованы как internal (только для внутреннего использования). Функции и переменные также могут быть с internal линковкой, если они заявлены как static. Такие типы объявления подразумевают, что они будут недоступны из другого файла. Если другой файл объявляет сущность с таким же именем, то оба объявления будут полностью независимы.

Вердикт
Использование internal линковки в .cc файлах предпочтительно для любого кода, к которому не обращаются снаружи (из других файлов). Не используйте подходы internal линковки в .h файлах.
Формат описания безымянного пространства имён полностью аналогичен именованному варианту. Не забывайте к закрывающей скобке написать комментарий, в котором имя оставьте пустым:

Функции: глобальные, статические внутри класса, вне класса

Предпочтительно размещать функции либо внутри класса, либо в некотором пространстве имён. Использование глобальных функций должно быть минимальным. Также не используйте класс для группировки различных функций, объявляя их статическими в одном классе: статические функции (по-правильному) должны использоваться для работы с экземплярами класса или его статическими данными.

За
Вообще функции (как статические, так и вне класса) довольно полезная штука, Кэп. И размещение функций либо в классе, либо в пространстве имён позволяет всё остальное содержать в чистоте (я про глобальное пространство имён).

Против
Иногда разумнее статические функции класса и функции вне класса сгруппировать в одном месте, в новом классе. Например, когда у них сложные зависимости от всего или им нужен доступ к внешним ресурсам.

Вердикт
Иногда полезно объявить функцию, не привязанную к экземпляру класса. И можно сделать либо статическую функцию в классе, либо внешнюю (вне класса) функцию. Желательно, чтобы функция-вне-класса не использовала внешних переменных и находилась в пространстве имён. Не создавайте классы только для группировки статических функций: это всё равно, что дать функциям некий префикс и группировка становится лишней.
Если требуется определить функцию: в .cc-файле; вне класса; используемой только в локальном файле — используйте internal линковку для ограничения области видимости.

Локальные переменные

Объявляйте переменные внутри функции в наиболее узкойобласти видимости, инициализируйте такие переменные при объявлении.
Язык C++ позволяет объявлять переменные в любом месте функции. Однако рекомендуется делать это в наиболее узкой (наиболее вложенной) области видимости, и по возможности ближе к первому использованию. Это облегчает поиск объявлений, проще узнать тип переменной и её начальное значение. Также рекомендуется использовать инициализацию, а не объявление с присваиванием. Примеры:

Переменные, необходимые только внутри кода if, while и for лучше объявлять внутри условий, тогда область их видимости будет ограничена только соответствующим блоком кода:

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

Возможно было бы более эффективно такую переменную (которая используется внутри цикла) объявить вне цикла:

Переменные: статические и глобальные

Объекты в статической области видимости/действия запрещены, кроме тривиально удаляемых. Фактически это означает, что деструктор должен ничего не делать (включая вложенные или базовые типы). Формально это можно описать, что тип не содержит пользовательского или виртуального деструктора и что все базовые типы и не-статические члены ведут себя аналогично (т.е. являются тривиально удаляемыми). Статические переменные в функциях могут быть динамически инициализированными. Использование же динамической инициализации для статических членов класса или переменных в области пространства имён (namespace) в целом не рекомендуется, однако допустимо в ряде случаев (см. ниже).
Эмпирическое правило: если глобальную переменную (рассматривая её изолированно) можно объявить как constexpr, значить она соответствует вышеуказанным требованиям.

Определение
Каждый объект имеет тот или иной тип времени жизни / storage duration, и, очевидно, это влияет на время жизни объекта. Объекты статического типа доступны с момента их инициализации до момента завершения программы. Такие объекты могут быть переменными в пространстве имён («глобальные переменные»), статическими членами классов, локальными переменными внутри функций со спецификатором static. Статические переменные в функциях инициализируются, когда поток выполнения кода проходит в первый раз через объявление; все остальные объекты статического типа инициализируются в фазе старта (start-up) приложения. Все объекты статического типа удаляются в фазе завершения программы (до обработки незавершённых(unjoined) потоков).
Инициализация может быть динамическая, т.е. во время инициализации делается что-то нетривиальное: например, конструктор выделяет память, или переменная инициализируется идентификатором процесса. Также инициализации может быть статической. Сначала выполняется статическая инициализация: для всех объектов статического типа (объект инициализируется либо заданной константой, либо заполняется нулями). Далее, если необходимо, выполняется динамическая инициализация.

За
Глобальные и статические переменные бывают очень полезными: константные имена, дополнительные структуры данных, флаги командной строки, логирование, регистрирование, инфраструктура и др.

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

Вердикт
Когда деструктор тривиальный, тогда порядок разрушения в принципе не важен. В противном случае есть риск обратиться к объекту после его разрушения. Поэтому, настоятельно рекомендуется использовать только переменные со статическим типом размещения (конечно, если они имеют тривиальный деструктор). Фундаментальные типы (указатели или int), как и массивы из них, являются тривиально разрушаемыми. Переменные с типом constexp также тривиально разрушаемые.

Отметим, что ссылка не есть сам объект, и, следовательно, к ним не применяются ограничения по разрушению объекта. Хотя ограничения на динамическую инициализацию остаются в силе. В частности, внутри функции допустим следующий код static T& t = *new T;.

Тонкости инициализации

Инициализация может быть запутанной: мало того, что конструктору нужно (желательно правильно) отработать, так есть ещё и предварительные вычисления:

Константная инициализация является рекомендуемой для большинства случаев. Константную инициализацию переменных со статическим размещением рекомендуется помечать как constexpr или атрибутом ABSL_CONST_INIT
. Любую переменную вне функции, со статическим размещением и без указанной выше маркировки следует считать динамически инициализируемой (и тщательно проверять на ревью кода).

Например, следующие инициализации могут привести к проблемам:

Динамическая инициализация переменных вне функций не рекомендуется. В общем случае это запрещено, однако, это можно делать если никакой код программы не зависит от порядка инициализации этой переменной среди других: в этом случае изменение порядка инициализации не может что-то поломать. Например:

Динамическая же инициализация статических переменных в функциях (локальных) допустима и является широко распространённой практикой.

Стандартные практики

Потоковые переменные

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

Определение
Начиная с C++11 переменные можно объявлять со спецификатором thread_local:

Каждая такая переменная представляется собой коллекцию объектов. Разные потоки работают с разными экземплярами переменной (каждый со своим экземпляром). По поведению переменные thread_local во многом похожи на Переменные со статическим типом размещения. Например, они могут быть объявлены в пространстве имён, внутри функций, как статические члены класса (как обычные члены класса — нельзя).
Инициализация потоковых переменных очень напоминает статические переменные, за исключением что это делается для каждого потока. В том числе это означает, что безопасно объявлять thread_local переменные внутри функции. Однако в целом thread_local переменные подвержены тем же проблемам, что и статические переменные (различный порядок инициализации и т.д.).
Переменная thread_local разрушается вместе с завершением потока, так что здесь нет проблем с порядком разрушения, как у статических переменных.

Вердикт
Переменные thread_local, заявленные внутри функций, можно использовать без ограничений, т.к. у них с безопасностью всё отлично. Отметим, что возможно использовать объявленную внутри функции переменную thread_local и вне функции. Для этого нужна функция доступа к переменной:

Переменные thread_local в классе или пространстве имён необходимо инициализировать константой времени компиляции (т.е. динамическая инициализация недопустима). Для этого необходимо аннотировать эти thread_local переменные с помощью ABSL_CONST_INIT
(или constexpr, но это лучше использовать пореже):

Переменные thread_local должны быть предпочтительным способом определения потоковых данных.

Примечания:
Изображение взято из открытого источника.

Источник

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

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