Исходные файлы и объявление переменных
Пример:
/* объявления переменной i на внутреннем уровне
с классом памяти static. */
/* исходный файл file1.c */
main()
{ ...
}
fun1()
{ static int i=0; ...
}
/* исходный файл file2.c */
fun2()
{ static int i=0; ...
}
fun3()
{ static int i=0; ...
}
Переменные класса памяти static могут быть инициализированы константным выражением. Если
явной инициализации нет, то такой переменной присваивается нулевое значение. При
инициализации константным адресным выражением можно использовать адреса любых внешних
объектов, кроме адресов объектов с классом памяти auto, так как адрес последних не
является константой и изменяется при каждом входе в блок. Инициализация выполняется один
раз при первом входе в блок.
Переменная, объявленная локально с классом памяти extern, является ссылкой на переменную
с тем же самым именем, определенную глобально в одном из исходных файлов программы. Цель
такого объявления состоит в том, чтобы сделать определение переменной глобального уровня
видимым внутри блока.
Пример:
/* объявления переменной i,являющейся именем внешнего
массива длинных целых чисел, на локальном уровне */
/* исходный файл file1.c */
main()
{ ...
}
fun1()
{ extern long i[]; ...
}
/* исходный файл file2.c */
long i[MAX]={0};
fun2()
{ ...
}
fun3()
{ ...
}
Объявление переменной i[] как extern в приведенном примере делает ее видимой внутри
функции fun1. Определение этой переменной находится в файле file2.c на глобальном уровне
и должно быть только одно, в то время как объявлений с классом памяти extern может быть
несколько.
Объявление с классом памяти extern требуется при необходимости использовать переменную,
описанную в текущем исходном файле, но ниже по тексту программы, т.е. до выполнения ее
глобального определения. Следующий пример иллюстрирует такое использование переменной с
именем st.
Пример:
main()
{ extern int st[]; ...
}
static int st[MAX]={0};
fun1()
{ ...
}
Объявление переменной со спецификатором extern информирует компилятор о том, что память
для переменной выделять не требуется, так как это выполнено где-то в другом месте
программы.
При объявлении переменных на глобальном уровне может быть использован спецификатор
класса памяти static или extern, а так же можно объявлять переменные без указания класса
памяти. Классы памяти auto и register для глобального объявления недопустимы.
Объявление переменных на глобальном уровне - это или определение переменных, или ссылки
на определения, сделанные в другом месте программы. Объявление глобальной переменной,
которое инициализирует эту переменную (явно или неявно), является определением переменной.
Определение на глобальном уровне может задаваться в следующих формах:
1. Переменная объявлена с классом памяти static. Такая переменная может быть
инициализирована явно константным выражением, или по умолчанию нулевым значением.
То есть обявления static int i=0 и static int i эквивалентны, и в обоих случаях
переменной i будет присвоено значение 0.
2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой
переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и
static int i=1 будут эквивалентны.
Переменная объявленная глобально видима в пределах остатка исходного файла, в котором
она определена. Выше своего описания и в других исходных файлах эта переменная невидима
(если только она не объявлена с классом extern).
Глобальная переменная может быть определена только один раз в пределах своей области
видимости. В другом исходном файле может быть объявлена другая глобальная переменная с
таким же именем и с классом памяти static, конфликта при этом не возникает, так как
каждая из этих переменных будет видимой только в своем исходном файле.
Спецификатор класса памяти extern для глобальных переменных используется, как и для
локального объявления, в качестве ссылки на переменную, объявленную в другом месте
программы, т.е. для расширения области видимости переменной. При таком объявлении
область видимости переменной расширяется до конца исходного файла, в котором сделано
объявление.
В объявлениях с классом памяти extern не допускается инициализация, так как эти
объявления ссылаются на уже существующие и определенные ранее переменные.
Переменная, на которую делается ссылка с помощью спецификатора extern, может быть
определена только один раз в одном из исходных файлов программы.