
Пример в листинге 12.3 служит иллюстрацией этого приема.

Обратите внимание, что trystat() инкрементирует каждую переменную после вывода ее значения. Запуск программы дает следующий вывод:
Начинается итерация 1: fade = 1 и stay = 1 Начинается итерация 2 : fade = 1 и stay = 2 Начинается итерация 3: fade = 1 и stay = 3
492 Глава 12
Статическая переменная stay запоминает, что ее значение было увеличено на 1, но переменная fade каждый раз начинается заново. Это отражает отличие в инициализации: fade инициализируется при каждом вызове trystat(), a stay — только один раз, когда функция trystat() компилируется. Статические переменные инициализируются нулем, если они были явно инициализированы другим значением.
Два следующих объявления выглядят похожими:
int fade = 1;
static int stay = 1;
Тем не менее, первый оператор в действительности является частью функции trystat() и выполняется каждый раз, когда функция вызвана. Это действие времени выполнения. Второй оператор на самом деле не относится к функции trystat(). Если вы примените отладчик для пошагового выполнения программы, то увидите, что программа как бы пропускает этот шаг. Причина в том, что после того, как программа загрузилась в память, статические переменные и внешние переменные уже находятся в нужных местах. Помещение оператора объявления в функцию trystat() сообщает компилятору, что только функции trystat() разрешено видеть данную переменную: это не оператор, который исполняется во время выполнения.
Использовать модификатор static для параметров функции нельзя:
int wontwork(static int flu); // не разрешено
Другим термином для статической переменной с областью видимости в пределах блока является “локальная статическая переменная”. Кроме того, если вы читали раннюю литературу по С, то обнаружите, что этот класс хранения называли внутренним статическим классом хранения . Тем не менее, слово внутренний применялось для указания на объявление внутри функции, а не на внутреннее связывание.
Статические переменные с внешним связыванием
Статическая переменная с внешним связыванием имеет область видимости в пределах файла, внешнее связывание и статическую продолжительность хранения. Такой класс иногда называют внешним классом хранения, а переменные этого тина — внешними переменными. Внешняя переменная создается путем размещения определяющего объявления за рамками всех функций. Согласно документации, внешняя переменная может дополнительно быть объявлена внутри функции, в которой она используется, с применением ключевого слова extern. Если какая-то внешняя переменная определена в одном файле исходного кода и используется во втором файле исходного кода, то объявление этой переменной во втором файле с ключевым словом extern является обязательным. Объявления выглядят следующим образом:

Классы хранения, связывание и управление памятью 493
Обратите внимание, что вы не обязаны указывать размерность массива в необязательном объявлении double Up. Это объясняется тем, что исходное объявление уже предоставило такую информацию. Группу объявлений extern внутри main() можно полностью опустить, т.к. внешние объявления имеют область видимости в пределах файла, поэтому они известны от места объявления и до конца файла. Однако они служат для документирования намерений применять эти переменные в main().
Если ключевое слово extern отсутствует в объявлении внутри функции, создается отдельная автоматическая переменная. То есть, замена
extern int Errupt; объявлением
int Errupt;
в main() приводит к тому, что компилятор создает автоматическую переменную но имени Errupt — отдельную локальную переменную, которая отличается от исходной переменной Errupt. Эта локальная переменная будет находиться в области видимости во время выполнения main(), но для других функций, таких как next(), расположенных в том же самом файле, в области видимости будет внешняя переменная Errupt. Короче говоря, переменная с областью видимости в пределах блока “скрывает” переменную с тем же самым именем, имеющую область видимости в пределах файла, когда происходит выполнение операторов в этом блоке. Если по какой-то маловероятной причине вам действительно необходима локальная переменная, имеющая тоже имя, что и глобальная переменная, можете воспользоваться в локальном объявлении спецификатором класса хранения auto, чтобы явно документировать свой выбор.
Читать дальше