Глобальная переменная


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

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

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

Локальная переменная — переменная, объявленная внутри какой-либо функции. Областью видимости локальных переменных является тело функции, в которой эта переменная объявлена. Локальная переменная может быть проинициализирована константой или выражением, соответствующими ее типу.

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


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

Глобальная переменная Задача 22. Составить программу, считающую тики.

Алгоритм решения Задачи 22, использующий глобальную переменную (countticks.mq4):

//--------------------------------------------------------------------
// countticks.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int Tick; // Глобальная переменная
//--------------------------------------------------------------------
int start() // Специальная функция start()
{
Tick++; // Счётчик тиков
Comment("Поступил тик № ",Tick); // Сообщение, содержащее номер
return; // Оператор выхода из start()
}
//--------------------------------------------------------------------

В этой программе используется всего одна глобальная переменная Tick. Она является глобальной, т.к. объявлена за пределами описания функции start(). Это значит, что от тика к тику значение этой переменной будет сохраняться. Рассмотрим подробности исполнения программы.


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

1. Объявление глобальной переменной Tick. Эта переменная не проинициализирована константой, поэтому её значение на этом этапе равно нулю.

2. Управление удерживается в клиентском терминале до поступления тика.

3. Поступил тик. Управление передаётся специальной функции start().

3.1. В рамках исполнения специальной функции start() управление передаётся оператору:

 Tick++; // Счётчик тиков

В результате исполнения этого оператора значение переменной Tick увеличится на 1 (целую единицу).

3.2. Управление передаётся оператору:

 Comment("Поступил тик № ",Tick); // Сообщение, содержащее номер

Исполнение стандартной функции Comment() приведёт к появлению сообщения:

Поступил тик № 1

3.3. Управление передаётся оператору:

 return; // Оператор выхода из start()

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

Далее события будут повторяться, начиная с пункта 2. Переменная Tick снова будет участвовать в вычислениях, однако на втором тике, в момент запуска на исполнение функции start(), её значение равно 1, поэтому результатом исполнения оператора:

 Tick++; // Счётчик тиков

будет новое значение переменной Tick — оно увеличится на 1 и теперь будет равно 2, поэтому исполнение функции Comment() приведёт к появлению сообщения:

Поступил тик № 2

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


В этом очень легко убедиться, запустив на выполнение эксперт, в котором переменная Tick открыта как локальная переменная (т.е. программа содержит алгоритмическую ошибку):

int start() // Специальная функция start()
{
int Tick; // Локальная переменная
Tick++; // Счётчик тиков
Comment("Поступил тик № ",Tick); // Сообщение, содержащее номер
return; // Оператор выхода из start()
}

С точки зрения синтаксиса в представленном коде ошибок нет. Эта программа может быть успешно скомпилирована и запущена на исполнение. И она будет работать, однако всё время будет сообщать один и тот же результат:

Поступил тик № 1

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

Статические переменные

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


 static int Number; // Статическая переменная целого типа

Ниже представлено решение задачи 22 с использованием статической переменной (эксперт staticvar.mq4):

//--------------------------------------------------------------------
// staticvar.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int start() // Специальная функция start()
{
static int Tick; // Статическая локальная перем
Tick++; // Счётчик тиков
Comment("Поступил тик № ",Tick); // Сообщение, содержащее номер
return; // Оператор выхода из start()
}
//--------------------------------------------------------------------

Статические переменные инициализируются однократно. Каждая статическая переменная может быть проинициализирована соответствующей ее типу константой (в отличие от простой локальной переменной, которая может быть проинициализирована любым выражением). Если явной инициализации нет, то статическая переменная инициализируется нулем. Статические переменные хранятся в постоянной области памяти программы, их значения не теряются при выходе из функции. Вместе с тем, статические переменные имеют ограничение, свойственное локальным переменным — областью видимости статической переменной остаётся функция, внутри которой эта переменная объявлена, в отличие от глобальных переменных, значение которых доступно из любого места программы. Легко увидеть, что программы countticks.mq4 и staticvar.mq4 дают одинаковый результат.

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

Внешние переменные


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

 extern int Number; // Внешняя переменная целого типа

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

Глобальная переменная Задача 23. Составить программу, в которой реализуются следующие условия: если цена достигла некоторого уровня Level и опустилась ниже этого уровня на n пунктов, то один раз сообщить об этом факте трейдеру.

Понятно, что поставленная задача предполагает необходимость изменения настроек, ведь сегодня цены уже не такие, как вчера, а завтра будут не такими, как сегодня. Чтобы обеспечить возможность изменения настроек в эксперте externvar.mq4 использованы внешние переменные:

//--------------------------------------------------------------------
// externvar.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
extern double Level = 1.2500; // Внешняя переменная
extern int n = 5; // Внешняя переменная
bool Fact_1 = false; // Глобальная перемен.
bool Fact_2 = false; // Глобальная перемен.
//--------------------------------------------------------------------
int start() // Спец. функция start
{
double Price = Bid; // Локальная перемен.
if (Fact_2==true) //Если сообщение уже..
return; //..было, то выходим

if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
Fact_1 = true; // Произошло событие 1

if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
NormalizeDouble(Level-n*Point,Digits))
My_Alert(); // Вызов польз. ф-ии

return; // Выход из start()
}
//--------------------------------------------------------------------
void My_Alert() // Пользовательс. ф-ия
{
Alert("Условия достигнуты"); // Сообщение
Fact_2 = true; // Произошло событие 2
return; // Выход из польз.ф-ии
}
//--------------------------------------------------------------------

В этой программе внешние переменные заданы в строках:


extern double Level = 1.2500; // Внешняя переменная
extern int n = 1; // Внешняя переменная

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

Глобальная переменная
Рис. 54. Окно свойств программы; здесь можно изменить значения переменных.

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

Если у пользователя возникла необходимость поменять значения внешних переменных в процессе работы программы, то необходимо открыть окно настроек и внести изменения.


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

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

При этом клиентский терминал последовательно запускает на исполнение специальную функцию deinit(), потом специальную функцию init(), а после этого, в момент поступления нового тика, запускает на исполнение специальную функцию start(). При исполнении функции deinit(), завершающей программу, внешние переменные будут иметь значения, полученные в предыдущем сеансе, т.е. те, которые были у них до открытия панели настроек эксперта. Перед исполнением специальной функции init() внешние переменные получат значения, установленные пользователем на панели настроек эксперта, и при исполнении функции init() внешние переменные будут иметь уже новые, установленные пользователем значения. Таким образом, новые значения внешних переменных вступают в силу с момента нового сеанса (init — start — deinit) работы эксперта, начинающегося с исполнения init().

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

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

 bool Fact_1 = false; // Глобальная перемен.
bool Fact_2 = false; // Глобальная перемен.
 double Price = Bid; // Локальная перемен.

Алгоритмически решение задачи выглядит так. Идентифицируются два события: первое — факт достижения ценой уровня Level, второе — факт того, что сообщение (о снижении ниже уровня Level на n пунктов) уже выдано. Эти события находят своё отражение в значениях переменных Fact_1 и Fact_2: если событие ещё не свершилось, то значение соответствующей переменной равно false, а если свершилось — true. В строках:

 if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
Fact_1 = true; // Произошло событие 1

определяется факт свершения первого события. Стандартная функция NormalizeDouble() позволяет производить вычисления со значениями действительных переменных с заданной точностью (соответствующей точности цены финансового инструмента). Если цена оказалась равной или выше заданного уровня, то факт первого события считается свершившимся, поэтому глобальной переменной Fact_1 присваивается значение истина. Программа составлена так, что переменная Fact_1, получив однажды значение истина, никогда не изменит его на ложь — для этого в программе нет соответствующего кода.

В строках:

 if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
NormalizeDouble(Level-n*Point,Digits))
My_Alert(); // Вызов польз. ф-ии

определяется необходимость выдачи сообщения. Если уже свершилось первое событие и цена опустилась на n пунктов ниже (меньше или равно) заданного уровня, то необходимо выдать сообщение — осуществляется вызов на исполнение пользовательской функции My_Alert(). В пользовательской функции, после собственно сообщения, отмечается факт того, что сообщение уже выдано, путём присвоения глобальной переменной Fact_2 значения true. После этого заканчивает работу пользовательская функция и вслед за ней и специальная функция start().

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

 if (Fact_2==true) //Если сообщение уже..
return; //..было, то выходим

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

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

book.mql4.com

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

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

#include <stdio.h>

void func1(void) , func2(void);

int count; /* count является глобальной переменной */

int main(void)
{
count = 100;
func1 ();
return 0; /* сообщение об удачном завершении работы */
}

void func1 (void)
{
func2 ();
printf(«счетчик %d», count); /* выведет 100 */
}

void func2(void)
{
int count;
for(count=1; count<10; count++)
putchar(‘  ‘);
}

Рассмотрим поближе данный фрагмент программы. Следует понимать, что хотя ни main(), ни func1() не объявляют переменную count, но они оба могут ее использовать. func2() объявляет локальную переменную count. Когда func2() обращается к count, она обращается только к локальной переменной, а не к глобальной. Надо помнить, что если глобальная и локальная переменные имеют одно и то же имя, все ссылки на имя внутри функции, где объявлена локальная переменная, будут относиться к локальной переменной и не будут иметь никакого влияния на глобальную,. это очень удобно. Если забыть об этом, то может показаться, что программа работает странно, даже если все выглядит корректно.

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

  1. Они используют память в течение всего времени работы программы, а не тогда, когда они необходимы.
  2. Использование глобальных переменных вместо локальных приводит к тому, что функции становятся более частными, поскольку они зависят от переменных, определяемых снаружи.
  3. Использование большого числа глобальных переменных может вызвать ошибки в программе из-за неизвестных и нежелательных эффектов.

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

Два способа написания mul( )
Общий Частный
int mul(int х, int у)
{
return(x*y); 
}
int х, у;
int mui(void)
{
return(x*y);
}

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

www.c-cpp.ru

Напомним, что каждый модуль (процедура, функция, программа) состоит из заголовка (procedure…, function…, program…) и блока.

Если блок какой-либо процедуры p1 содержит внутри процедуру p2, то говорят, что p2 вложена в p1.

Пример.

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

Пример.

Константы, переменные, типы, описанные в блоке program, называются глобальными. Казалось бы, проще иметь дело вообще только с глобальными переменными, описав их все в program. Но использование локальных переменных позволяет системе лучше оптимизировать программы, делать их более наглядными и уменьшает вероятность появления ошибок.

При написании программ, имеющих вложенные модули, необходимо придерживаться следующих правил:

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

Локализация переменных дает программисту большую свободу в выборе идентификаторов. Так, если две процедуры a и b полностью отделены друг от друга (т.е. не вложены одна в другую), то идентификаторы в них могут быть выбраны совершенно произвольно, в частности, могут повторяться. В этом случае совпадающим идентификаторам соответствуют разные области памяти, совершенно друг с другом не связанные.

Пример.

Если один и тот же идентификатор описан в блоке b и второй раз описан во вложенном в b блоке c, то надо помнить, что эти два одинаковых идентификатора соответствуют разным ячейкам памяти.

Глобальным переменным i и a отводятся две ячейки памяти. Первыми выполняются операторы a := 2.0 и i := 15. Затем вызывается процедура p(a). В процессе работы p отводится ячейка для локальной переменной i и туда засылается число 3. После окончания работы процедуры p эта ячейка i программой «забывается». После возврата на оператор writeln программа знает только одну ячейку i – глобальную, т.е. ту, которая содержит число 15. Поэтому программа выдаст на печать i = 15, a = 23.0, т.к. a = 3 + 10 * 2.

Если локальная и глобальная переменная принадлежат к одному и тому же сложному типу, то этот тип надо описать в разделе type, а сами переменные описывать через этот общий тип.

Пример.

В этом примере переменные a и b описаны через общий тип ab. Если же локальная и глобальная переменные описаны одинаково, но не через общий тип, то программа может «не понять», что эти переменные принадлежат одному типу.

Пример.

В этом примере переменные a и b – одинаковые массивы, т.е. типы этих переменных одинаковы, но программа, тем не менее, «не считает», что a и b принадлежат одному типу. Это происходит из-за того, что описание массивов дано в разных блоках.

pas1.ru

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

Обычно глобальные переменные объявляют в верхней части кода, ниже директив #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 с неконстантными и константными переменными:

Тест

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

Ответ

ravesli.com

Область видимости переменных в C++

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

В C++ существуют отдельные блоки, которые начинаются с открывающей скобки ({) и заканчиваются соответственно закрывающей скобкой (}). Такими блоками являются циклы (for, while, do while) и функции.

Если переменная была создана в таком блоке, то ее областью видимости будет являться этот блок от его начала (от открывающей скобки —  { ) и до его конца (до закрывающей скобки — } ) включая все дочерние блоки созданные в этом блоке.

В примере ниже, программист ошибся с областью видимости:

  • Он создал переменную j во втором цикле.
  • Использовав ее в первом цикле for он вынудил компилятор сообщить об ошибке (переменной j больше нет, поскольку второй цикл закончил свою работу).

А вот ошибки в строке 6 нет, поскольку второй цикл находится в первом цикле (является дочерним блоком первого цикла)  и поэтому переменная b может спокойно там использоваться.

Глобальные переменные в C++

Глобальными переменными называются те переменные, которые были созданы вне тела какого-то блока. Их можно всегда использовать во всей вашей программе, вплоть до ее окончания работы. В примере ниже мы создали две глобальные переменные global и global_too и использовали их в функции summa:

Вот, что выведет данная программа:

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

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

Локальные переменные — это переменные созданные в блоках. Областью видимости таких переменных является блоки ( и все их дочерние ), а также их область видимости не распространяется на другие блоки. Как ни как, но эти переменные созданы в отдельных блоках.

Из этого можно сделать вывод: у нас есть возможность создавать переменные с одинаковыми именами, но в разных блоках (или другими словами, чтобы их область видимости не совпадала друг с другом).

В примере выше блоком где была создана локальная переменная b является цикл for (2 — 5). А вот если бы мы захотели вывести переменную b вне блока for, компилятор сообщил бы нам об ошибке, подробнее об этом говорится ниже.

Распространенной ошибкой среди начинающих программистов является использование локальных переменных в других блоках.  Например ниже мы решили использовать переменную cost в функции summa, хотя мы ее создали в совершенно другой функции — main.

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

Глобальная переменная уступает локальной

Если мы создадим глобальную переменную и с таким же именем локальную, то получится, что там где была создана локальная переменная будет использоваться именно локальная переменная, а не глобальная. Так как локальная переменная считается по приоритету выше глобальной. Давайте разберем, как это работает на примере ниже:

Мы создали глобальную переменную str со значением «You lucky!» и локальную переменную с таким же названием в функции message, но с другим значением — «You very lucky man!». Если мы вызовем функцию message, то результатом будет:

А вот, если мы вызовем функцию sait_message то результатом будет:

Вот так глобальная переменная уступает локальной!

Мы советуем вам не создавать переменные с одинаковыми именами, поскольку в будущем вам будет тяжело разобраться в коде, если там будут присутствовать одинаковые переменные.

Глобальный оператор разрешения

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

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

Чтобы использовать глобальный оператор разрешения нужно применять данную конструкцию:

В примере ниже вы можете увидеть, как работает глобальный оператор разрешения:

Получится вот такой результат, если мы вызовем функцию message:

codelessons.ru

Глобальные переменные

Глобальная переменная — это такая, которая объявлена вне тела какой-либо функции. Все глобальные переменные являются свойствами глобального объекта (в браузере – это window).

  var car = "Audi";  console.log(window.car); // "Audi"  

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

  function myF() {   car = "Audi"; // переменная car, созданная в функции без ключевого слова var   var bus = "Volvo"; // переменная bus  }  // переменная car доступна вне функции  console.log(car); // "Audi"  console.log(window.car); // "Audi"  // переменная bus не доступна вне функции  console.log(bus); // ReferenceError: bus is not defined  

Но это только справедливо не для строго режима. В строгом режиме необходимо обязательно объявлять переменные.

  'use strict';  function myF() {   car = "Audi";  }  console.log(car); // Uncaught ReferenceError: car is not defined  // глобальная переменная browser не объявлена  browser = "Firefox"; // Uncaught ReferenceError: car is not defined  

К глобальной переменной можно обратиться внутри функции.

  'use strict';  var car = "Audi"; // глобальная переменная car  function myF() {   console.log(car); // получение значения глобальной переменной  }  myF(); // "Audi"  

  // глобальная переменная numberUsers  var numberUsers=0;  // функция, при вызове которой изменяется значение глобальной переменной numberUsers  function getUsers1() {   numberUsers=5; // присвоим значение 5 глобальной переменной numberUsers    return numberUsers; // вернём в качестве результата функции значение глобальной переменной   }  // функция, при вызове которой изменяется значение глобальной переменной numberUsers  function getUsers2() {   numberUsers+=10; // увеличим значение на 10 глобальной переменной numberUsers    return numberUsers;  }  //вызовем функцию getUser1(), которая вернёт значение глобальной переменной numberUsers  console.log("numberUsers (getUser1) = "+getUsers1());  // вызовем функцию getUser2(), которая возвратит значение глобальной переменной numberUsers  console.log ("numberUsers (getUser2) = "+getUsers2());  //выведем значения глобальной переменной numberUsers  console.log ("numberUsers = "+numberUsers);  
JavaScript — Использование глобальной переменной на примере
JavaScript - Использование глобальной переменной на примере

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

Локальные переменные – это такие, которые определены с помощью ключевого слова var внутри тела какой-либо функции. Локальные переменные существуют только внутри тела функции, в которой они объявлены, а также доступны внутри её дочерних функций.

  function getViews() {   // локальная переменная, созданная внутри функции getViews и не доступная за её пределами   var numberViews = 37;   // вернём в качестве результата данной функции значение локальной переменной numberViews   return numberViews;  }  // вызов функции getViews, которая вернёт значение переменной numberViews  console.log("Функция getViews вернула значение: "+ getViews());  // попробуем получить значение переменной вне функции  console.log("Значение переменной numberViews: "+ numberViews);  
JavaScript — Пример, демонстрирующий использование локальной переменной
JavaScript - Пример, демонстрирующий использование локальной переменной

Основные моменты при работе с переменными в JavaScript

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

  • при каждом вызове одной и той же функции, локальные переменные создаются заново;
  • в разных функциях можно создать переменные с одинаковыми именами, но это будут 2 совершенно разные переменные;
  • при выполнении функции предпочтение отдаётся не глобальной, а локальной переменной, если она имеет точно такое же имя;
  • использование глобальных переменных при написании JavaScript сценариев желательно свести к минимуму или вообще не использовать.

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

  // создание глобальной переменной numberUsers и её инициализация числом 0  var numberUsers=0;   function getUsers1() {   // создание локальной переменной numberUsers внутри функции getUsers1   var numberUsers;   // изменение значения локальной переменной numberUsers   numberUsers=5;   // вернём в качестве результата значение локальной переменной numberUsers    return numberUsers;  }  function getUsers2() {   // создание локальной переменной numberUsers в функции getUsers2   var numberUsers;   // изменение значения локальной переменной numberUsers на значение 10   numberUsers+=10;   return numberUsers;  }  // вызовем функцию getUser1, которая вернёт значение переменной numberUsers, созданной в этой функции  console.log("numberUsers (getUser1) = "+getUsers1());  // вызовем функцию getUser2, которая вернёт значение переменной numberUsers, созданной в этой функции  console.log("numberUsers (getUser2) = "+getUsers2());  // выведем в консоль значение глобальной переменной numberUsers  console.log("numberUsers = "+numberUsers);  
JavaScript — Пример, показывающий разницу между локальной и глобальной переменной
JavaScript - Пример, показывающий разницу между локальной и глобальной переменной

itchief.ru

HTML + JavaScript и CSS = страница

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

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

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

Существенны:

  • данные, а это не только и не столько переменные PHP;
  • код, а это совсем не только PHP.

PHP — это язык вставок, но использование глобальных данных в локальных функциях важно. Оценивая роль любого серверного языка, трудно получается поднимать его значение выше места, который он занимает, но часто это реально необходимо. Место PHP — вставка внутри страницы даже в предельном случае, когда страница создана исключительно силами самого языка в полном объеме. Страница никогда не бывает одинокой и однородной:

  • в ней есть HTML;
  • элементам назначены обработчики JavaScript;
  • теги описаны посредством CSS;
  • имеются: код JavaScript, JSON, иные вставки.

Все это пестрое сообщество должно определять, что следует разобрать браузеру и как построить дерево DOM, которое определит внешний вид и функционал страницы.

Вставки PHP: описания и алгоритмы

Есть две принципиально различные идеи, которые реализует PHP. Первая позволяет включать/выключать блоки HTML-текста от участия в потоке вывода. Вторая — непосредственный код: описания переменных, алгоритмы и масса локальных функций, нуждающихся в глобальных данных.

В любом случае могут быть использованы глобальные переменные PHP. Во вставках первого типа переменные только используются. Во вставках второго типа они могут быть изменены.

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

При просмотре HTML-текста PHP исполняет код последовательно — общее правило интерпретатора, которого программисту не следует придерживаться во избежание непредвиденных ошибок. Важно представлять: все вставки обрабатываются последовательно.

В примере (1) выполнена вставка описания только одной переменной $cPageName. В примере (2) в том же месте (блок «HEAD») производится инициализация множества глобальных переменных PHP из массива данных GET и POST — $_REQUEST.

Во втором примере выполняется вставка PHP-кода из файлов: scQS.php и save-visit-to-page.php, при этом первый файл загружает и инициализирует систему объектов приложения, второй файл выполняет регистрацию посещения данной страницы.

Оба файла также создают глобальные переменные классов. PHP не систематизирует объявление и использование переменных. Управление всеми объявлениями выполняет программист.

Одно кардинально отличное обстоятельство

Массивы глобальных данных $_GET, $_POST, $_REQUEST, $_SERVER доступны всегда, но не всегда содержат нужные данные. На данные сессии и куки тоже можно рассчитывать. Можно считать все это оригинальным способом объявления глобальной переменной. PHP сам занимается управлением данных, помещенных в эти массивы.

Манипулируя значениями в ходе передачи (GET, POST), в куках, в сессиях, можно передавать данные между страницами или странице самой себе совершенно безопасно: ничего не пропадет, это несложно, хотя выглядит странно и громоздко.

Но важно понимать и знать одно крайне важное обстоятельство. Глобальные переменные PHP и SERVER «живут» только один раз: в момент обращения! Когда браузер открывает или обновляет страницу: начинается «жизнь». Как только страница улетает в браузер, «жизнь» прекращается.

Обращений будет один миллион значит «жизней». Ровно столько раз SERVER даст возможность PHP создать и использовать все то, что описал программист и именно по алгоритмам этого программиста.

Никакой связи между «жизнями» нет!

Кардинальные, но эффективные хитрости

Программисту на PHP глобальная переменная нужна всегда, а не только тогда, когда браузер зашел на веб-ресурс или посетитель решил обновить страницу. Программист вообще может желать, чтобы вся созданная им система объектов существовала не от случая к случаю, а постоянно.

Веб-ресурс разработан, создан. Значит, все его страницы должны «жить», если не вечно, то хотя бы в контролируемом диапазоне времени. Между визитами посетителей тоже.

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

Что касается безопасности, это забота программиста. Задача простая и решаемая. Что касается абсурдности, это не так. Используя JSON, механизм AJAX и собственное воображение, можно перенести центр тяжести с сервера в браузер и создать там тот вариант отображения данных на то количество глобальных переменных PHP, которое необходимо.

Вложение областей видимости

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

В этом примере в конструкторе и функции объекта scStartView() доступны все переменные, которые перечислены за ключевым словом global. Какое именно они несут в себе значение, как именно их можно использовать, знает только программист. На PHP глобальные переменные в функцию приходят только по именам. Иное определяет программист.

Под телом функции, объекта или метода объекта следует понимать все то, что находится внутри «{ … }». Фигурные скобки — это границы локальной области видимости. Функция, описанная внутри другой функции, имеет свою область видимости. Никакой код не может проникнуть в локальную область видимости.

Транзит данных внутри кода

Вопрос — как сделать глобальную переменную PHP, переводит на момент времени вызова кода. В остальном PHP не ограничивает программиста. Можно использовать куки, сессии и глобальные массивы. Оптимальны — JSON & AJAX и недра браузера. Последний вариант подходит лучше всего, но требует хорошего знания JavaScript.

Принципиально нет и никогда не было разделения программирования на браузерное (frontend) и серверное (backend). Хотя с позиций рекламы, имиджа и способа объяснить заказчику, что работа на копейку стоит аж два рубля это имеет реальный смысл.

Всякий PHP-программист обязан иметь прочные знания о том, что такое HTML и как строится DOM, следовательно, начальное знание по JavaScript должно быть в порядке вещей. Программист JavaScript и только — нонсенс, хотя бывает реальная потребность в исключительно узкой квалификации. Полные знания и клиентской части, и серверной — нормальное положение вещей.

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

Часто важно управлять данными между различными (множественными) посетителями. Хранить и осуществлять передачу (транзит) данных в течение времени — очень ответственная и важная процедура. Транзит данных внутри кода во времени расширяет возможности программирования.

Самый простой пример решения PHP: создать глобальную переменную можно банально в текстовом файле. Это не сложно. Это делается в момент посещения страницы (как пример). Читается при открытии страницы (все вставки берутся из файлов). Ничто не мешает изменять файлы в процессе посещения одним посетителем, в ожидании посещения вторым.

Вопросы безопасности и сохранности данных

Любая глобальная переменная — потенциальная угроза. Украсть переменную PHP — сложно, если невозможно. Посмотреть переменную JavaScript можно почти всегда. Если в браузере и на сервере все кодируется, для злоумышленника создается преграда, которая оказывает отрицательное влияние и на разработчика.

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

Хороший выход предлагает использование объектно-ориентированного программирования, когда создается такая система объектов, которая сама определяет необходимые в данный момент времени переменные.

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

Место PHP и его переменных

Формировать страницу — главная задача PHP. Использование систем управления сайтами (CMS) ограничивает программиста и навязывает ему определенную концепцию управления глобальными переменными. Любая CMS — это масса ее собственных переменных, причем 99 % из них не требуются для создания конкретного сайта.

В чистом варианте серверная часть сайта — это база данных и файлы. Место, где хранится информация, которую браузер «распознает» как веб-ресурс. На самом деле ему в этом помогает программист, кодирующий что-то на PHP, уточняющий что-то на JavaScript. К этому прикладывается верстка HTML/CSS.

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

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

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

Фантазии разработчика

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

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

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

www.syl.ru

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

Вто же время, является допустимым и не приводит к ошибке описание переменных

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

int x = 5;

/* x типа int */

void main(void)

{

double x = 3.14159265357898; /* x типа double */

{

char x = ‘A’;

/* x типа char */

}

/* опять x типа double */

}

/* опять x типа int */

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

studfiles.net


You May Also Like

About the Author: admind

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

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.