1.12. Классы памяти. Общие правила описания. Оператор typedef

Кроме своего типа каждая переменная в языке С характеризуется также клас­сом памяти. Существует четыре класса памяти :

auto - автоматические переменные; extern - внешние переменные; static - статические переменные; register - регистровые переменные. Описатель класса памяти может указываться в описаниях переменных слева от типа:

класс памяти тип имя = { список значений } ;

Автоматические переменные определены в той функции или блоке, где они описаны и инициализируются при каждом выполнении функции (блока). Такие объекты "живут" лишь во время работы блока (функции).

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

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

Регистровые переменные могут храниться в регистрах центрального процес­сора (что приводит к исключительно быстрой обработке этих переменных), в остальном они аналогичны автоматическим. При недостатке регистровой памяти описатель register игнорируется, но к любым переменным, описанным как реги­стровые, неприменима операция "адрес".

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

В С++ предусмотрен доступ к глобальным переменным, скрытым локальны­ми переменными с тем же именем. Операция разрешения области видимости :: позволяет в таких ситуациях воспользоваться глобальной переменной. Напри­мер: int x=5;

void main() { int x=3;

printf(" Локальная x= %d\n",x); printf('Tлобальная x= %d\n",::x); }

В описаниях кроме имен переменных и имен типов используются модифи­каторы : * - указатель, () - функция и [] - массив, причем в описаниях сложных объектов модификаторов может быть много, что затрудняет чтение и запись та­ких конструкций. Для правильной интерпретации описаний используются сле­дующие правила приоритетов :

1) чем ближе модификатор к имени, тем выше его приоритет;

2) [] и () имеют более высокий приоритет, чем *;

3) можно использовать круглые скобки для повышения приоритета моди­фикатора *.

Модификаторы доступа vo1ati1e и const позволяют сообщить компилятору об изменчивости или постоянстве определяемого объекта. Если переменная описана как const, то она недоступна в других модулях проекта, подобно статическим переменным, и не может быть изменена в процессе выполнения программы. Константа должна быть инициализирована при описании. С помощью модифи­катора const создаются типизированные именованные константы, которые в от­личие от символических констант, определенных директивой #define, подлежат контролю типов. Например:

const doub1e PI=3.141528; const char yes='Y'; Одно из важных применений переменных типа const - защита параметров функ­ции от модификации, если аргумент передается по ссылке. Модификатор vo1ati1e сообщает компилятору, что значение таких подвижных объектов может быть изменено скрытно от компилятора каким-либо фоновым процессом. Например, при обработке прерывания глобальная переменная, содержащая системное время компьютера, может изменить свое значение. Компилятор не должен помещать такие переменные в регистровую память. Пример объявления : vo1ati1e unsigned timer;

Так же, как и в языке PASCAL, в языке С программист имеет возможность создавать собственные именованные типы, для чего используется оператор typedef . Запись оператора совпадает с записью описания переменной, только вместо имени переменной задается имя типа и описание предваряется ключевым словом typedef. Оператор typedef может находиться внутри функции - тогда он действует только в данной функции, либо вне функций, и тогда он действует до конца файла. Идентификатор, заданный в операторе typedef, становится именем типа и в дальнейшем может использоваться в описаниях переменных. Например, вместо описания

#define SIZE 3

int b[][SIZE]={1,2,3,4,5,6,7,8,9};

можно использовать описание #define SIZE 3

typedef int ARRAY[][SIZE]; ARRAY b={1,2,3,4,5,6,7,8,9};

Отметим, что декларация typedef не создает новый тип (как в языке PASCAL), она лишь сообщает новое имя уже существующего типа.