
- •Глава 3. Производные типы данных. Массивы.
- •3.3. Многомерные массивы.
- •3.4. Базовые алгоритмы обработки двумерных массивов.
- •Глава 4. Функции.
- •4.1. Стандартное определение функции.
- •4.2. Локальные переменные.
- •4.3. Размещение тела функции. Прототип функции.
- •4.4. Глобальные переменные.
- •4.5. Классы памяти.
- •5.1. Директива # define.
- •5.2. Использование макроопределений с аргументами.
- •5.3. Директива # include. Включение файла.
- •5.4. Условная компиляция.
4.5. Классы памяти.
Классы памяти языка Си/Си++ позволяют управлять ключевыми механизмами программы, они дают возможность определить, с какими функциями связаны какие переменные и как долго значение переменной сохраняется в программе.
Каждая переменная имеет тип, кроме того, каждая переменная принадлежит к некоторому классу памяти. Для описания класса памяти используются четыре ключевых слова:
auto - автоматическая;
extern - внешняя;
static - статическая;
register - регистровая.
Класс памяти позволяет установить два факта. Во-первых, определить какие функции имеют доступ к переменной (т.е. область действия). Во-вторых, установить, как долго переменная находится в памяти.
Рассмотрим каждый класс отдельно.
Автоматическая память.
Автоматическая память используется для распределения в памяти локальных переменных (принцип организации – стек). Автоматическая переменная начинает существовать при вызове функции, содержащей ее. При завершении работы функции память, отведенная под ее локальные переменные, становится недоступной. Еще раз подчеркнем, что выделение памяти происходит при входе в блок, а при выходе из блока память освобождается. По умолчанию используется класс памяти auto.
Статическая память.
Статическая память выделяется под переменные, локализованные внутри блока, но не освобождается при выходе из блока. Инициализация статической переменной происходит только при первом вхождении в блок. Если инициализация переменной отсутствует, то ей автоматически присваивается нулевое значение.
Пример описания статической переменной:
fc()
{
static int S;
...
}
Внешняя память.
Переменная, описанная вне функции, является внешней. Внешнюю переменную можно описать внутри функции, используя ключевое слово extern. Используется данный класс памяти для выделения места под глобальные переменные. Повторим, что глобальную переменную можно объявить вне программных блоков, как уже было рассмотрено выше. Помимо этого, глобальную переменную можно объявить, используя ключевое слово extern. Обычно это делается, когда программные модули хранятся в отдельных файлах и следовательно отдельно компилируются.
Следующие примеры демонстрируют четыре возможные комбинации описаний:
Пример 1.
int EX; // глобальная переменная
main()
{
extern int EX;
....
}
// вспомогательная функция
F()
{
extern int EX;
....
}
// Переменная ЕХ в основной и вспомогательной функции объявлена как внешняя,
//предполагается использование этой переменой как «доступной всем»
Пример 2.
int EX;
main()
{
extern int EX;
....
}
F()
{
// переменная ЕХ не объявляется, но ее можно использовать
....
}
В этом случае переменная ЕХ доступна вспомогательной функции по умолчанию.
Пример 3.
int EX;
main()
{
// переменная ЕХ не объявляется ....
}
F()
{
// переменная ЕХ не объявляется
....
}
В этом случае переменная ЕХ доступна функциям main() и F() по умолчанию, так как она объявлена как глобальная.
Пример 4.
int EX;
main()
{
int EX; // переменная ЕХ – локальная и доступна только функции main()
// и эта переменная «перекрыла» одноименную глобальную переменную ЕХ
….
}
F()
{
int EX; // переменная ЕХ – локальная и доступна только функции F()
….
}
Примечание.
Внешняя переменная может быть описана как статическая. Разница между внешней переменной и внешней статической переменной заключается в области их действия. Обычная внешняя переменная может использоваться функциями в любом файле, внешняя статическая переменная может использоваться функциями только того же файла.
4.Регистровые переменные. Регистровые переменные располагаются в регистрах центрального процессора, где доступ к ним и работа с ними выполняются гораздо быстрее, чем в памяти. В остальном регистровые переменные не отличаются от автоматических. Но, описывая регистровую переменную необходимо помнить, что компилятор сравнивает запрошенное количество с доступным количеством регистров, может оказаться, что свободных регистров нет. В этом случае заявленная переменная становится автоматической.
Так какой же класс применять? Как правило, все-таки – автоматический. Из соображений защиты необходимо организовать работу каждой функции автономно, насколько это возможно. При использовании внешних переменных могут возникнуть проблемы, связанные с тем, что функции несанкционированно изменяют значения переменных из-за ошибок в программе, которые сложно отследить.
Вернемся к определению функции в языке Си/Си++. Необходимо отметить, что всем именам функций программы по умолчанию присваивается внешний класс памяти – extern, поэтому каждая функция глобальна.
Глава 5. Препроцессор языка Си/Си++.
Препроцессор языка Си/Си++ работает на первом шаге компиляции и обеспечивает следующие возможности языка:
1. включение файла
2. макроподстановка
3. условная компиляция.
Для управления препроцессором используются директивы препроцессора. каждая директива помещается на отдельной строке и начинается с символа #.
В языке определены следующие препроцессорные директивы:
# define - определение символической константы, определение макроса, определение макро функции
# include - включение файла
# undef - отменяет последнее определение поименованного макроса
# if - проверка условия выражения
# ifdef - проверка определенности идентификатора
# ifndef - проверка неопределенности идентификатора
# else - начало альтернативной ветви для # if
# endif - окончание директивы # if
# elif - составная директива # else/# if
#error - формирование текста сообщения об ошибке трансляции
# - пустая директива