Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЗФ_ОАиП / Лекции ГГУ Скорины - Программирование.doc
Скачиваний:
204
Добавлен:
21.03.2016
Размер:
2.27 Mб
Скачать

20.7. Статические локальные переменные

Локальные переменные, объявленные со спецификатором класса памяти static, обеспечивают возможность сохранить значение переменной при выходе из блока и использовать его при повторном входе в блок. Такая переменная имеет глобальное время жизни и область видимости внутри блока, в котором она объявлена. В отличие от переменных с классом auto, память для которых выделяется в стеке, для переменных с классом static память выделяется в сегменте данных, и поэтому их значение сохраняется при выходе из блока. Для локальной переменной, описанной со спецификатором static, компилятор выделяет память точно так же, как и для глобальных переменных – в начале работы программы. Коренное отличие статических локальных от глобальных переменных заключается в том, что статические локальные переменные видны только внутри блока, в котором они объявлены. Говоря коротко, статические локальные переменные – это локальные переменные, сохраняющие свое значение между вызовами функции.

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

int f() {

static int a = 0; // по умолчанию тоже равно 0

a = a + 10;

return a;

}

void main () {

printf(“Вызов функции 1: a = %d”, f()); // a = 10

printf(“Вызов функции 2: a = %d”, f()); // a = 20

printf(“Вызов функции 3: a = %d”, f()); // a = 30

}

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

Для чего все-таки такие переменные придуманы? Эти переменные создаются один раз за время работы программы, и один раз инициализируются – либо 0, либо тем значением, которое вы задали. А раз они живут независимо от функции, значит в одном вызове функции в такую переменную можно что-то положить, а в следующем – это что-то использовать.

int f() {   static int ncalls = 1;   // который раз функция вызывается?

 printf("number of calls %d\n", ncalls++);   ... }

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

Другое полезное использование статических локальных переменных – возможность выполнять какие-то подготовительные операции только один раз.

void f() {

static int first = 0;

if (first == 0) {

first = 1;

...

}

...

}

void main() {

int i;

for (i=0; i<1000; i++)

f();

}

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

20.8. Регистровые переменные

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

Переменная, объявленная с классом памяти register, имеет ту же область видимости, что и переменная auto. Число регистров, которые можно использовать для значений переменных, ограничено возможностями компьютера, и в том случае, если компилятор не имеет в распоряжении свободных регистров, то переменной выделяется память как для класса auto, но компилятор получает указание позаботиться о быстродействии операций с ними. В языке С с помощью оператора & нельзя получить адрес регистровой переменной, потому что она может храниться в регистре процессора, который не имеет адреса.

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