Объявление переменной на внешнем уровне

Объявление переменной на внешнем уровне

Объявления переменной на внешнем уровне используют спецификации класса памяти static и extern или вообще опускают их. Спецификации класса памяти auto и register не допускаются на внешнем уровне.

Объявления переменных на внешнем уровне—это либо определения переменных, либо объявления, т.е. ссылки на определения, сделанные в другом месте.

Определение внешней переменной—это объявление, которое вызывает выделение памяти для этой переменной и инициализирует ее (явно или неявно). Определение на внешнем уровне может задаваться в следующих различных формах:

1) Переменная может быть определена путем ее объявления со спецификацией класса памяти static. Такая переменная может быть явно инициализирована константным выражением. Если инициализатор отсутствует, то переменная автоматически инициализируется нулевым значением во время компиляции. Таким образом, каждое из объявлений:

static int k = 16;

и

static int k;

рассматривается как определение.

2) Переменная может быть определена, если спецификация класса памяти в ее объявлении опущена, и переменная явно инициализируется, например,

int j = 3;

Область действия переменной, определенной на внешнем уровне, распространяется от точки, где она определена, до конца исходного файла. Переменная недоступна выше своего определения в том же самом исходном файле. На другие исходные файлы программы область действия переменной распространяется лишь в том случае, если ее определение не содержит спецификации класса памяти static и если в других исходных файлах имеется ее объявление.

Если в объявлении переменной задана спецификация класса памяти static, то в других исходных файлах могут быть определены другие переменные с тем же именем и любым классом памяти. Эти переменные никак не будут связаны между собой, поскольку каждое определение static доступно только в пределах своего исходного файла.

Спецификация класса памяти extern используется для объявления переменной, определенной где-то в другом месте программы. Такие объявления используются в случае, когда нужно распространить на данный исходный файл область действия переменной, определенной в другом исходном файле, либо сделать переменную доступной в том же исходном файле выше ее определения. Область действия переменной распространяется от места объявления до конца исходного файла.

В объявлениях, которые используют спецификацию класса памяти extern, инициализация не допускается, так как они ссылаются на переменные, значения которых определены в другом месте.

Каждая переменная внешнего уровня обязательно должна быть определена один и только один раз в каком-либо из исходных файлов, составляющих программу.

Существует одно исключение из правил, описанных выше. Можно опустить в объявлении переменной на внешнем уровне и спецификацию класса памяти, и инициализатор. Например, объявление int n; будет вполне корректным внешним объявлением. Это объявление имеет различный смысл в зависимости от контекста:

1) Если в каком-то другом исходном файле программы (возможно, в другом исходном файле) есть определение на внешнем уровне переменной с таким же именем, то данное объявление является ссылкой на это определение. В этом случае объявление аналогично объявлению со спецификацией класса памяти extern.

2) Если же такого определения переменной в программе нет, то данное объявление само считается определением переменной. На этапе компоновки программы переменной выделяется память, которая инициализируется нулевым значением. Если в программе имеется более одного объявления переменной с одним и тем же именем, то размер выделяемой памяти будет равен размеру наиболее длинного типа среди всех объявлений этой переменной. Например, если программа содержит два неинициализированных объявления переменной i на внешнем уровне int i; и char i;, то память будет выделена под переменную i типа int.

Примечание. В описании языка Си, данном его разработчиками в [1], отсутствовала ясная трактовка понятий объявления и определения глобальной переменной. Это привело к тому, что различные компиляторы языка Си используют различные схемы разбора подобных ситуаций. Схема разбора, описанная в данном разделе, рассматривает глобальную переменную как общий блок, разделяемый несколькими исходными файлами. Глобальная переменная фактически представляет собой единую область памяти, которая разделяется несколькими исходными файлами, причем в каждом из них переменная может иметь различный тип.

Рекомендуется всегда инициализировать объявления переменных на внешнем уровне в файлах, которые предназначены для помещения в библиотеку. Это повышают вероятность выявления случаев нежелательного совпадения имен внешних переменных в библиотечном файле и пользовательской программе. Если переменная в программе пользователя также инициализирована, то компоновщик обнаружит два инициализированных объявления одной и той же глобальной переменной и сообщит об ошибке.

Возможно наличие в одном исходном файле на внешнем уровне нескольких объявлений переменной с одним и тем же именем. Следующая таблица позволяет определить реакцию компилятора языка Си в различных ситуациях изменения спецификации класса памяти в объявлении. Слово "пусто" в таблице означает ситуацию отсутствия спецификации класса памяти. Очевидно, что компилятор СП MSC строже ограничивает возможность переопределения класса памяти переменной.

Класс 1 Класс 2 СП TC СП MSC
extern static static static
static пусто static ошибка
static extern static static
пусто static static ошибка

Пример: /* ИСХОДНЫЙ ФАЙЛ 1 */

/* объявление i, ссылающееся на данное ниже определение i */

extern int i;

main()

{

i = i + 1;

printf("%d ", i); /* значение i равно 4 */

next();

}

int i = 3; /* определение i */

next()

{

printf("%d ", i); /* значение i равно 5 */

other());

}

/* ИСХОДНЫЙ ФАЙЛ 2 */

/* объявление i, ссылающееся на определение i в первом исходном файле */

extern int i;

other()

{

i = i + 1;

printf("%d ", i); /* значение i равно 6 */

}

Два исходных файла в совокупности содержат три внешних объявления i. Только в одном объявлении содержится инициализация:

int i = 3; — глобальная переменная i определена с начальным значением 3.

Самое первое объявление extern в первом исходном файле делает глобальную переменную i доступной прежде ее определения в файле. Без этого объявления функция main не могла бы использовать глобальную переменную i. Объявление переменной i во втором исходном файле делает глобальную переменную i доступной во втором исходном файле.

Все три функции выполняют одно и то же действие: увеличивают i на 1 и печатают полученное значение. Значения распечатываются с помощью стандартной библиотечной функции printf. Печатаются значения 4, 5 и 6.

Если бы переменная i не была инициализирована ни в одном из объявлений, она была оы неявно инициализирована нулевым значением при компоновке. В этом случае программа напечатала бы значения 1, 2 и 3.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

var - Объявление локальной переменной

Из книги автора

var - Объявление локальной переменной varИспользуется для объявления локальных переменныхСинтаксис:var variableName1 [= value1] [...,variableNameN [=valueN]];Аргументы:Описание:Создание переменной называется ее объявлением. Объявление - это этап формального создания переменной. Когда впервые


На высшем уровне

Из книги автора

На высшем уровне В мае 2010 года технология Punycode обрела воплощение в самых верхних доменных рядах. Появились первые многоязычные «официальные» домены верхнего уровня (арабские и кириллические).Перед этим Punycode, по заданию ICANN, тщательно испытали в лабораториях и выяснили,


14. Объявление переменной на внутреннем уровне с классом памяти static

Из книги автора

14. Объявление переменной на внутреннем уровне с классом памяти static В качестве примера рассмотрим объявление переменной i на внутреннем уровне с классом памяти static.исходный файл filel.сmain(){}fun1(){static int i = 0; исходный файл file2.c fun2(){static int i = 0; }fun3(){static int i = 0; }В этом примере


15. Объявление переменной, которая служит именем внешнего массива

Из книги автора

15. Объявление переменной, которая служит именем внешнего массива Рассмотрим пример: объявление переменной i, которая служит именем внешнего массива длинных целых чисел, на локальном уровне.исходный файл file1.cmain(){…}fun1(){extern long i[];…}/* исходный файл file2.c */long i[MAX] =


Объекты на уровне понятий

Из книги автора

Объекты на уровне понятий Если вам трудно ассоциировать объекты с графическими элементами, ячейками рабочего листа или кнопками панели инструментов, представляйте себе объекты как материальные предметы. Вы же можете представить, как вырезаете ножницами из листа бумаги


О внешнем виде форм и элементов управления

Из книги автора

О внешнем виде форм и элементов управления Хотя вы можете изменить параметры, относящиеся к внешнему виду форм и элементов управления, с помощью программного кода, чаше всего делать это не имеет смысла. Лучше воспользоваться диалоговым окном Properties для выбора всех


Редактирование на уровне сегментов

Из книги автора

Редактирование на уровне сегментов Редактирование сплайнов на уровне сегментов позволяет выполнить следующие операции:• Detach (Отделить) – отделяет сегменты, преобразуя их в самостоятельные формы;• Delete (Удалить) – удаляет сегменты;• Divide (Разделить) – добавляет


Редактирование на уровне сплайнов

Из книги автора

Редактирование на уровне сплайнов Чтобы отредактировать сплайн на уровне входящих в его состав сплайнов, нужно перейти на уровень подобъектов Spline (Сплайн), щелкнув в стеке модификаторов на соответствующей строке. Выделенный подобъект будет окрашен красным цветом.При


Объявление простой переменной

Из книги автора

Объявление простой переменной Синтаксис:<спецификация типа> <идентификатор> [,<идентификатор>…];Объявление простой переменной определяет имя переменной и ее тип. Имя переменной задается <идентификатором>. <Спецификация типа> задает тип переменной. Тип


Объявление переменной перечислимого типа

Из книги автора

Объявление переменной перечислимого типа Синтаксис:enum [<тег>]{<список-перечисления>} <описатель>[,<описатель>…];enum <тег> <идентификатор> [<идентификатор>…];Объявление переменной перечислимого типа задает имя переменной и определяет список именованных


Объявление переменной на внутреннем уровне

Из книги автора

Объявление переменной на внутреннем уровне Любая из четырех спецификаций класса памяти может быть использована для объявления переменной на внутреннем уровне. Если спецификация класса памяти опущена в объявлении переменной на внутреннем уровне, то подразумевается


3.2.2. Имя переменной

Из книги автора

3.2.2. Имя переменной Имя переменной, или идентификатор, может состоять из латинских букв, цифр и символа подчеркивания. Прописные и строчные буквы в именах различаются. Язык С++ не ограничивает длину идентификатора, однако пользоваться слишком длинными именами типа


Блокировка на уровне таблицы

Из книги автора

Блокировка на уровне таблицы Транзакция может быть сконфигурирована для блокирования всей таблицы. Существует два приемлемых способа сделать это в DSQL: установив уровень изоляции транзакции в SNAPSHOT TABLE STABILITY (известный также как согласованный режим, поддерживаемый


Блокировка на уровне таблицы

Из книги автора

Блокировка на уровне таблицы Уровень изоляции транзакции TABLE STABILITY (или согласованная изоляция) предоставляет полную блокировку таблицы по записи, включая зависимые таблицы. Этот уровень слишком агрессивен для интерактивных приложений.Более предпочтительным является


Редактирование на уровне таблицы

Из книги автора

Редактирование на уровне таблицы Существует два уровня редактирования таблицы: уровень таблицы и уровень ячейки. В обоих случаях необходимо использовать управляющие маркеры.Вы можете просто щелкнуть на любой линии таблицы, чтобы отобразились маркеры управления на