Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

prog / Лекции / 23. Классы памяти

.pdf
Скачиваний:
24
Добавлен:
13.05.2015
Размер:
138.66 Кб
Скачать

Классы памяти

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

auto – так называемая автоматическая переменная, размещаемая в оперативной памяти компьютера. Этот класс памяти используется по умолчанию, если иное не указано явно при описании переменной. Локальные переменные располагаются в сегменте стека, память для них выделяется на вершине стека автоматически при входе в функцию или блок и освобождается автоматически при выходе из функции или блока. Для глобальных переменных модификатор auto не применим, так как определяет переменную с локальным временем жизни. На практике модификатор auto используется крайне редко из-за отсутствия необходимости в нем.

register – регистровая переменная. Отличие от автоматической заключается в том, что переменная располагается в регистрах процессора. Это используется для ускорения доступа к переменной, однако, является скорее просьбой, чем директивой – компилятору не всегда удается выделить регистр процессора для хранения переменной из-за: малого количества регистров; большого количества переменных, объявленных как регистровые; большого размера типа данных этой переменной; если регистровые переменные запрещены параметрами компилятора. Регистровой может быть только локальная переменная, но к ней не применима операция определения адреса. В примере слева показано правильное использование регистровой переменной i для ускорения работы цикла, а справа – неправильное, так как попытка определить адрес регистровой переменной x в выражении &x при вызове функции scanf приведет к ошибке при компиляции:

register int i;

register int x;

...

...

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

scanf("%d", &x);

...

...

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

double x;

...

{

static double p = 0.0;

double t;

/* переменная для временного хранения */

t = (p + x) / 2;

/* результата */

p = x;

/* сохранить значение "на будущее" */

x = t;

/* присвоить результат */

}

 

...

 

extern – внешняя переменная. Только при использовании данного модификатора, описание переменной является объявлением, во всех остальных случаях – определением. Модификатор extern указывает на то, что память для этой переменной выделяется где-то в другом месте программы при ее определении, а сама переменная при этом должна быть определена как глобальная и не статическая. Таким образом, описание внешней переменной является своеобразной ссылкой на «настоящую» переменную. Это позволяет расширить область действия глобальной переменной и обращаться к ней в другом модуле, либо в том же модуле, но до ее определения (выше по тексту). В последнем случае эта переменная может быть определена и как статическая, так как она используется в пределах одного модуля:

#include <stdio.h>

#include <stdio.h>

void main(void)

void main(void)

{

{

int k = 1;

int k = 1;

{

{

extern int x;

extern int x;

k = x;

k = x;

}

}

printf("%d\n", k);

printf("%d\n", k);

}

}

int x = 5;

static int x = 5;

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

extern int errno;

void main(void)

{

... /* использование переменной errno */

}

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