4.6 Статические переменные
Переменные sp и val в файле stack.с , а также buf и bufp в getch.с находятся в личном пользовании функций этих файлов, и нет смысла открывать к ним доступ кому-либо еще. Указание static, примененное к внешней переменной или функции, ограничивает область видимости соответствующего объекта концом файла. Это способ скрыть имена. Так, переменные buf и bufp должны быть внешними, поскольку их совместно используют функции getch и ungetch , но их следует сделать невидимыми для "пользователей" функций getch и ungetch .
Статическая память специфицируется словом static, которое помещается перед обычным объявлением. Если рассматриваемые нами две функции и две переменные компилируются в одном файле, как в показанном ниже примере:
static char buf[BUFSIZE]; /* буфер для ungetch */
static int bufp = 0; /* след. свободная позиция в buf */
int getch(void) {…}
void ungetch(int с) {…}
то никакая другая программа не будет иметь доступ ни к buf , ни к bufp , и этими именами можно свободно пользоваться в других файлах для совсем иных целей. Точно так же, помещая указание staticперед объявлениями переменных sp и val , с которыми работают только push и pop , мы можем скрыть их от остальных функций.
Указание staticчаще всего используется для переменных, но с равным успехом его можно применять и к функциям. Обычно имена функций глобальны и видимы из любого места программы. Если же функция помечена словом static, то ее имя становится невидимым вне файла, в котором она определена.
Объявление staticможно использовать и для внутренних переменных. Как и автоматические переменные, внутренние статические переменные локальны в функциях, но в отличие от автоматических, они не возникают только на период работы функции, а существуют постоянно. Это значит, что внутренние статические переменные обеспечивают постоянное сохранение данных внутри функции.
Упражнение 4.11. Модифицируйте функцию getop так, чтобы отпала необходимость в функции ungetch . Подсказка: используйте внутреннюю статическую переменную.
4.7 Регистровые переменные
Объявление registerсообщает компилятору, что данная переменная будет интенсивно использоваться. Идея состоит в том, чтобы переменные, объявленные register, разместить на регистрах машины, благодаря чему программа, возможно, станет более короткой и быстрой. Однако компилятор имеет право проигнорировать это указание. Объявление registerвыглядит следующим образом:
register int х;
register char с;
и т. д. Объявление registerможет применяться только к автоматическим переменным и к формальным параметрам функции. Для последних это выглядит так:
f(register unsigned m, register long n)
{
register int i;
…
}
На практике существуют ограничения на регистровые переменные, что связано с возможностями аппаратуры. Располагаться в регистрах может лишь небольшое число переменных каждой функции, причем только определенных типов. Избыточные объявления registerни на что не влияют, так как игнорируются в отношении переменных, которым не хватило регистров или которые нельзя разместить на регистре. Кроме того, применительно к регистровой переменной независимо от того, выделен на самом деле для нее регистр или нет, не определено понятие адреса (см. главу 5). Конкретные ограничения на количество и типы регистровых переменных зависят от машины.
Поскольку функции в Си нельзя определять внутри других функций, он не является языком, допускающим блочную структуру программы в том смысле, как это допускается в Паскале и подобных ему языках. Но переменные внутри функций можно определять в блочно-структурной манере. Объявления переменных (вместе с инициализацией) разрешено помещать не только в начале функции, но и после любой левой фигурной скобки, открывающей составную инструкцию. Переменная, описанная таким способом, "затеняет" переменные с тем же именем, расположенные в объемлющих блоках, и существует вплоть до соответствующей правой фигурной скобки. Например, в
if (n › 0) {
int i; /* описание новой переменной i */
for (i = 0; i ‹ n; i++)
…
}
областью видимости переменной i является ветвь if , выполняемая при n›0; и эта переменная никакого отношения к любым i , расположенным вне данного блока, не имеет. Автоматические переменные, объявленные и инициализируемые в блоке, инициализируются каждый раз при входе в блок. Переменные static инициализируются только один раз при первом входе в блок.
Читать дальше