return 0;
}
//---------------------Второй файл---------------------
#include <iostream>
static int sum=0, count=0;
int r_avg(int i)
{
sum = sum + i;
count++;
return sum / count;
}
void reset()
{
sum = 0;
count = 0;
}
В этой версии программы переменные sum и count являются глобально статическими, т.е. их глобальность ограничена вторым файлом. Итак, они используются функциями r_avg() и reset(), причем обе они расположены во втором файле. Этот вариант программы позволяет сбрасывать накопленную сумму (путем установки в исходное положение переменных sum и count), чтобы можно было усреднить другой набор чисел. Но ни одна из функций, расположенных вне второго файла, не может получить доступ к этим переменным. Работая с данной программой, можно обнулить предыдущие накопления, введя число -2. В этом случае будет вызвана функция reset(). Проверьте это. Кроме того, попытайтесь получить из первого файла доступ к любой из переменных sum или count. (Вы получите сообщение об ошибке.)
Итак, имя локальной static-переменной известно только функции или блоку кода, в котором она объявлена, а имя глобальной static-переменной — только файлу, в котором она "обитает". По сути, модификатор static позволяет переменным существовать так, что о них знают только функции, использующие их, тем самым "держа в узде" и ограничивая возможности негативных побочных эффектов. Переменные типа static позволяют программисту "скрывать" одни части своей программы от других частей. Это может оказаться просто супердостоинством, когда вам придется разрабатывать очень большую и сложную программу.
Важно! Несмотря на то что глобальные static-переменные по-прежнему допустимы и широко используются в С++-коде, стандарт C++ возражает против их применения. Для управления доступом к глобальным переменным рекомендуется другой метод, который заключается в использовании пространств имен. Этот метод описан ниже в этой книге.
Возможно, чаще всего используется спецификатор класса памяти register. Для компилятора модификатор register означает предписание обеспечить такое хранение соответствующей переменной, чтобы доступ к ней можно было получить максимально быстро. Обычно переменная в этом случае будет храниться либо в регистре центрального процессора (ЦП), либо в кэше (быстродействующей буферной памяти небольшой емкости). Вероятно, вы знаете, что доступ к регистрам ЦП (или к кэш-памяти) принципиально быстрее, чем доступ к основной памяти компьютера. Таким образом, переменная, сохраняемая в регистре, будет обслужена гораздо быстрее, чем переменная, сохраняемая, например, в оперативной памяти (ОЗУ). Поскольку скорость, с которой к переменным можно получить доступ, определяет, по сути, скорость выполнения вашей программы, для получения удовлетворительных результатов программирования важно разумно использовать спецификатор register.
Спецификатор register в объявлении переменной означает требование оптимизировать код для получения максимально возможной скорости доступа к ней.
Формально спецификатор register представляет собой лишь запрос, который компилятор вправе проигнорировать. Это легко объяснить: ведь количество регистров (или устройств памяти с малым временем выборки) ограничено, причем для разных сред оно может быть различным. Поэтому, если компилятор исчерпает память быстрого доступа, он будет хранить register-переменные обычным способом. В общем случае неудовлетворенный register-запрос не приносит вреда, но, конечно же, и не дает никаких преимуществ хранения в регистровой памяти.
Поскольку в действительности только для ограниченного количества переменных можно обеспечить быстрый доступ, важно тщательно выбрать, к каким из них применить модификатор register. (Только правильный выбор может повысить быстродействие программы.) Как правило, чем чаще к переменной требуется доступ, тем большая выгода будет получена в результате оптимизации кода с помощью спецификатора register. Поэтому объявлять регистровыми имеет смысл управляющие переменные цикла или переменные, к которым выполняется доступ в теле цикла. На примере следующей функции показано, как register-переменная типа int используется для управления циклом. Эта функция вычисляет результат выражения mе для целочисленных значений с сохранением знака исходного числа (т.е. при m = -2 и е = 2 результат будет равен -4).