Классы памяти и области видимости переменных
Классы памяти
Класс памяти определяет «время жизни» объекта. Под объектом понимается идентификатор переменной, функция либо указатель функции. Кроме этого, класс памяти в совокупности с местоположением переменной в программе, определяет область видимости переменной.
Различают два вида объектов: глобальные и локальные.
Объекты с глобальным временем жизни существуют и имеют значение на протяжении всего времени исполнения программы.
Все функции и их указатели – глобальные объекты. Локальные объекты «захватывают» новую область памяти всякий раз, когда управление передается блоку, в котором они описаны.
Если переменная описана вне всяких блоков, то она считается глобальной. Это описание на так называемом внешнем уровне.
Блок- это описание функции, составная команда, либо часть программы, заключенная в фигурные скобки
{
это блок
}
Блоки могут быть вложенными:
{
{
это вложенный блок
}
}
Переменные, описанные внутри некоторого блока, являются локальными. При каждом входе в блок им выделяется новая область памяти, а при выходе из блока память освобождается и значение переменной, следовательно, теряется. Локальные объекты видны с момента их описания до конца блока.
Если при выходе из блока нужно сохранить значение переменной, то ее следует описать как статическую в данном блоке, например:
{
static int a;
...
}
Теперь при выходе из блока переменная а будет сохранять в памяти свое место и значение и будет «видна» только в этом блоке, а также в блоках вложенных в него.
Глобальные объекты видны с момента их описания до конца файла всем функциям (блокам).
Если имя локального объекта (переменной) совпадает с именем глобального объекта, то локальный объект маскирует глобальный в этом блоке.
Область действия меток - функция, в которой метка используется.
Пример 9.1: Область видимости переменных.
#include <stdio. h>
int k = 1; /* k = 1 */
void main(void)
{
printf(“k = %d \n”, k); // Результат: k = 1
{
//1-й вложенный блок
int k = 2, m = 5;
printf(“ k = %d \t m = %d \n”, k, m); // Результат: k =2, m = 5
{
//2-й вложенный блок
int k=0;
printf(“ k = %d \t m = %d \n”, k, m); // Результат: k=0, m=5
}
printf(“ k = %d \n”, k); // Результат: k=2
}
printf(“ k = %d \n”, k); // Результат:k=1
}
В приведенной программе четыре уровня видимости:
1) внешний уровень;
2) тело функции main();
3) 1-й вложенный блок;
4) 2-й вложенный блок
Внешний уровень – уровень файла. Объект внешнего уровня виден “всем в файле”. Время его жизни – глобальное. На локальном уровне внешний объект может быть переопределен.
Описатели классов памяти
Различают два класса объектов: глобальные и локальные, но используют четыре описателя классов: extern, static, auto и register. Назначение и применение их приведено в табл. 9.1
Таблица 9.1
Классы памяти
Класс памяти | Ключевое слово | Время действия | Область действия |
1. Автоматический | auto | временно | локальная |
2. Регистровый | register | временно | локальная |
3. Статический | static | постоянно | локальная |
4. Внешний | extern | постоянно | глобальная (все файлы) |
5.Внешний статический | static | постоянно | глобальная (один файл) |
Классы 1, 2 и 3 описываются внутри функций; Классы 4 и 5 описываются вне функций.
По умолчанию (без спецификаторов класса памяти) переменные, описанные внутри функции, являются автоматическими. Переменные, описанные вне функций по умолчанию - глобальные.
Класс памяти extern указывает, что глобальная переменная описана где-то в другом месте (в этом или другом файле). Таким образом, описатель extern позволяет только сослаться на описание, сделанное в другом месте.
Для того, чтобы описание extern было корректным, необходимо чтобы описание самой переменной существовало только один раз в любом из файлов, образующих текст программы, например:
Файл 1 файл 2 файл 3
… … …
float p=0.33; extern float p; extern float p;
Замечание: Описание вида: extern тип имя_ переменной = значение; недопустимо.
Если переменная внутри функции имеет класс памяти extern, то она может быть описана только после описания этой функции, например:
Неправильно Правильно
… …
main () main ()
{ {
… …
} }
6 func_1() func_1()
{ {
k = k+2 extern int k;
} k = k+2;
int k = 10 }
… int k =10;
…
Ошибка состоит в том, что область видимости переменной начинается с точки ее описания.
Глобальные переменные могут быть инициализированы:
явно: int k = 10; static float a = 20.52;
неявно int k; static float a;
При неявной инициализации переменным присваиваются нулевые значения.
Класс памяти static на внешнем уровне маскирует описание переменных внутри файла, в котором они описаны. Другим файлам они не недоступны.
Класс памяти register предполагает хранение переменной во внутреннем регистре процессора. Время жизни и область видимости регистровой переменной такая же, как и у автоматической. Если компилятор не может разместить эту переменную в регистре, то она трактуется как автоматическая. По умолчанию значение регистровых переменных не определено.
К регистровой переменной нельзя применить операцию & - определение адреса. Их нельзя описывать на внешнем уровне.