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

20.2. Спецификаторы класса памяти

В языке С есть четыре спецификатора класса памяти: auto, extern, static и register. Эти спецификаторы сообщают компилятору, в каком месте он должен разместить соответствующие объекты в памяти. Как уже говорилось, таких мест всего три: сегмент данных (постоянная память), стек и регистры процессора.

Объекты классов auto и register имеют локальное время жизни. Переменные класса памяти auto располагаются в стеке. Переменные класса памяти register располагаются, если это возможно, в регистрах процессора, или же в стеке.

Спецификаторы static и extern объявляют объекты с глобальным временем жизни. Память под переменные с глобальным временем жизни выделяется в сегменте данных.

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

Общая форма объявления переменных при этом такова:

спецификатор_класса_памяти тип имя_переменой;

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

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

При объявлении переменных на глобальном уровне может быть использован спецификатор класса памяти static или extern. Классы памяти auto и register для глобального объявления недопустимы.

20.3. Область видимости функций

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

Правила определения области видимости для функций отличаются от правил видимости для переменных:

1. Функция, объявленная как static, видима в пределах того файла, в котором она определена. Каждая функция может вызвать другую функцию с классом памяти static из своего исходного файла, но не может вызвать функцию, определенную с классом static в другом исходном файле. Разные функции с классом памяти static, имеющие одинаковые имена, могут быть определены в разных исходных файлах, и это не ведет к конфликту.

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

3. Если в объявлении функции отсутствует спецификатор класса памяти, то по умолчанию принимается класс extern.

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

Глобальные переменные – это переменные, которые определены за пределами любой функции. Если при описании глобальной переменной нет ее инициализации, то начальное значение такой переменной будет равно 0.

Объявление переменных на глобальном уровне – это или определение переменных, или ссылки на определения, сделанные в другом месте программы.

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

int x = 10; // глобальная переменная x = 10

int y; // глобальная переменная y = 0

void main () {

... y++; ...

}

void f1 () {

x = 5;

y = 2;

}

Здесь переменные x и y видны и в функции main(), и в функции f1(). Что значит: «функция видит переменную»? Это значит, что внутри функции можно обращаться к этой переменной.

void main () {

...

}

void f1 () {

x = 15; // компилятор выдаст ошибку, переменная ещё не объявлена

}

int x = 5; // определение глобальной переменной

int getX () {

return x; // getХ видит переменную x

}

Переменная x объявлена после функций main() и f1(), а значит, в этих функциях она не видна.

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

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

extern int x; // объявляем глобальную переменную, теперь

// ее можно использовать ниже в этом файле

void main () {

...

}

void f1 () {

x = 15; // компилятор уже не выдаст ошибку

}

int x = 5; // определение глобальной переменной

int getX () {

return x; // getХ видит переменную x

}

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

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

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

В объявлениях с классом памяти extern не допускается инициализация, так как эти объявления ссылаются на уже существующие и определенные ранее переменные.

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

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