Память для переменной с автоматической продолжительностью хранения выделяется, когда поток управления входит в блок, содержащий объявление переменной, и освобождается после покидания этого блока потоком управления. Неинициализированная переменная такого рода имеет случайное значение. Память для переменной со статической продолжительностью хранения выделяется на этапе компиляции и сохраняется на все время выполнения программы. Неинициализированная переменная такого рода получает значение 0. Переменная с областью видимости в пределах блока является локальной по отношению к блоку, содержащему объявление. Переменная с областью видимости в пределах файла известна всем функциям в файле (или единице трансляции), которые находятся после ее объявления. Если переменная с областью видимости в пределах файла имеет внешнее связывание, то она может использоваться другими единицами трансляции в программе. Если переменная с областью видимости в пределах файла имеет внутреннее связывание, то она может применяться только внутри файла, в котором она объявлена.
Ниже показана короткая программа, в которой используются все классы хранения. Код разнесен на два файла (листинг 12.5 и листинг 12.6), так что вы должны провести многофайловую компиляцию. (За деталями обращайтесь в главу 9 или в руководство по компилятору.) Главная цель программы заключается в демонстрации всех классов хранения, а не в том, чтобы предложить проектную модель; в качественном проекте нет нужды в переменных с областью видимости в пределах файла.
Листинг 12.5. Программа parta.c

500 глава 12
Листинг 12.6. Программа partb.c

В этой программе статическая переменная с областью видимости в пределах блока, имеющая имя subtotal, накапливает промежуточную сумму значений, передаваемых функции accumulate(), а переменная total с областью видимости в пределах файла и внутренним связыванием накапливает общую сумму. Функция accumulate() выводит значения total и subtotal каждый раз, когда ей передается неположительное значение; в таких ситуациях она также сбрасывает subtotal в 0. Прототип accumulate() в программе parta.c обязателен, т.к. файл содержит вызов функции accumulate(). В файле partb.c прототип не обязателен, поскольку функция в нем определена, но не вызывается. В этой функции также применяется внешняя переменная count для отслеживания количества итераций цикла while, выполненных в main(). (Кстати, это хороший пример того, как не следует использовать внешнюю переменную, потому что она нежелательным образом переплетает код в parta.c с кодом в partb. с.) В файле parta. с функции main() и report_count() совместно осуществляют доступ к count.
Вот результаты пробного запуска:
Введите положительное целое число (0 для завершения): 5 итерация цикла: 1 subtotal: 15; total: 15
Введите положительное целое число (0 для завершения): 10 итерация цикла: 2 subtotal: 55; total: 70
Введите положительное целое число (0 для завершения) : 2 итерация цикла: 3 subtotal: 3; total: 73
Введите положительное целое число (0 для завершения): 0 Цикл выполнен 3 раз(а)
Классы хранения, связывание и управление памятью 501
Классы хранения и функции
Функции также имеют классы хранения. Функция может быть либо внешней (по умолчанию), либо статической. (В стандарте С99 добавлена третья возможность — встраиваемая функция, которая обсуждается в главе 16.) Доступ к внешней функции могуг получать функции в других файлах, но статическая функция может применяться только внутри файла, где она определена. Рассмотрим, например, файл со следующими прототипами функций:
double gamma(double); /* по умолчанию внешняя */
static double beta(int, int);
extern double delta(double, int);
Функции gamma() и delta() могут использоваться функциями в других файлах, которые являются частью программы, но beta() — нет. Из-за такого ограничения функции beta() одним файлом в остальных файлах можно применять другие функции с этим же именем. Причина использования класса хранения static связана с созданием функций, закрытых в отношении конкретного модуля, благодаря чему устраняется возможность конфликта имен.
Обычная практика предусматривает применение ключевого слова extern при объявлении функции, определенной в другом файле. Главным образом это касается ясности, т.к. объявление функции предполагается как extern, если только не указано ключевое слово static.
Читать дальше