• Статический, внешнее связывание. Переменная, которая определена как внешняя по отношению к любой функции и без использования модификатора класса хранения static, принадлежит к классу хранения “статический, внешнее связывание”. Она имеет статическую продолжительность хранения, область видимости в пределах файла и внешнее связывание. Такая переменная инициализируется только один раз на этапе компиляции. Если она не инициализирована явно, ее биты устанавливаются в 0.
• Статический, внутреннее связывание. Переменная, которая определена как внешняя по отношению к любой функции и с указанием модификатора класса хранения static, принадлежит к классу хранения “статический, внутреннее связывание”. Она имеет статическую продолжительность хранения, область видимости в пределах файла и внутреннее связывание. Такая переменная инициализируется только один раз на этапе компиляции. Если она не инициализирована явно, ее биты устанавливаются в 0.
Выделение памяти обеспечивается функцией malloc() (или родственной ей), которая возвращает указатель на блок памяти, имеющий запрошенное количество байтов. Эту память можно сделать доступной для повторного использования, вызвав функцию free() с передачей адреса в качестве аргумента.
Квалификаторами типа являются const, volatile и restrict. Квалификатор const указывает на константные данные. В случае применения с указателями const может определять, что константным является сам указатель или же данные, на которые указатель ссылается, в зависимости от места его размещения внутри объявления. Квалификатор volatile говорит о том, что данные могут изменяться процессами, внешними по отношению к программе. Он предназначен для предупреждения компилятора о том, что он должен избегать оптимизаций, которые предполагались бы в от сутствие volatile. Квалификатор restrict также введен по причинам, связанным с оптимизацией. Указатель, помеченный с помощью restrict, идентифицируется как единственное средство доступа к блоку данных.
Классы хранения, связывание и управление памятью 525
Вопросы для самоконтроля
Ответы на вопросы для самоконтроля приведены в приложении А.
1. Какие классы хранения создают переменные, локальные по отношению к функции, которая их содержит?
2. Какие классы хранения создают переменные, которые сохраняются на протяжении выполнения содержащей их программы?
3. Какой класс хранения создает переменные, которые могут использоваться в нескольких файлах? Только в одном файле?
4. Какой вид связывания имеют переменные с областью видимости в пределах блока?
5. Для чего используется ключевое слово extern?
6. Взгляните на следующий фрагмент кода:
int * p1 = (int *) malloc(100 * sizeof(int));
Чем от него отличается показанный ниже оператор в смысле конечного результата?
int * p1 = (int*) calloc(100, sizeof(int));
7. Каким функциям известна каждая переменная в следующем коде? Если ли в коде ошибки?

8. Что выведет следующая программа?
526 глава 12
int main(void)
{
extern char color;
printf("color в main() равно %c\n", color); first();
printf("color в main() равно %c\n", color); second();
printf("color в main!) равно %c\n", color); return 0;
}
void first(void)
{
char color; color = 'R';
printf("color в first() равно %c\n", color);
void second(void)
{
color = 'G';
printf("color в second(); равно %c\n", color);
}
9. Файл начинается со следующих объявлений:
static int plink;
int value_ct(const int arr[], int value, int n);
а. Что говорят эти объявления о намерениях программиста?
б. Увеличит ли защиту значений в вызывающей программе замена объявлений
int и int n объявлениями const int и const int n?
Упражнения по программированию
1. Перепишите программу из листинга 12.4 так, чтобы в ней не использовались глобальные переменные.
2. Расход бензина обычно измеряется в милях на один галлон в США и в литрах на 100 километров в Европе. Ниже приведена часть программы, которая предлагает пользователю выбрать режим (метрический или американский), а затем выполняет сбор данных и вычисляет расход топлива:
// pel2-2b.с
// компилировать вместе с ре12-2а.с #include
#include "pel2-2a.h" int main(void)
{
int mode;
printf ("Введите 0 для метрического режима или 1 для американского режима: "); scanf("%d", &mode); while (mode >= 0)
{
set_mode(mode); get_infо(); show_infо();
printf ("Введите 0 для метрического режима или 1 для американского режима"); printf(" (-1 для завершения): "); scanf("%d", &mode);
}
Классы хранения, связывание и управление памятью 527
printf("Программа завершена.\n"); return 0;
}
Ниже показан пример вывода:
Введите 0 для метрического режима или 1 для американского режима: О Введите пройденное расстояние в километрах: 600 Введите объем израсходованного топлива в литрах: 78.8 Расход топлива составляет 13.13 литров на 100 км.
Читать дальше