Этот шаг посвящен особенностям использования класса памяти extern.
Oбъекты, описанные внутри функции с добавлением класса памяти extern, либо описанные вне функции без указания класса памяти, относятся к внешним объектам.
Внешние объекты хранятся вне любой функции, входящей в состав программы, и существуют в течение выполнения всей программы. Они могут быть использованы для передачи значений между различными (в том числе и отдельно компилируемыми) функциями.
Сами функции также являются внешними объектами, поскольку правила языка C++ не позволяют определять одни функции внутри других.
Внешние переменные можно инициализировать только выражениями с константами и указателями на ранее описанные объекты. По умолчанию (если не задана инициализация) внешние объекты получают нулевые начальные значения.
#include <iostream.h> int i; /* Определение i */ int j=100; /* Определение j */ void main () { extern int i; /* Описание i */ extern int j; /* Описание j */ /* ------------------------- */ cout << "i = " << i << endl; cout << "j = " << j << endl; }
Результаты работы программы:
i=0 j=100
Важно различать описание внешнего объекта и его определение. Описание указывает свойства объекта (тип, размеры и т.д.); определение же вызывает еще и отведение памяти, и установку начального значения, если используется инициализация.
Например, появившиеся вне определения какой-либо функции строчки
int max; char save [maxline];
определяют внешние переменные max и save, вызывают отведение для них места в памяти.
В то же время строчки
extern int max; extern char save[];
описывают в данном блоке переменную max как int, a save как массив типа char (размеры которого указаны в другом месте программы), но не создают переменных и не отводят для них места в памяти.
Во всех файлах, составляющих исходную программу, должно содержаться только одно определение внешней переменной; другие файлы могут содержать описания extern для доступа к ней.
Любая инициализация внешней переменной производится только в определении. Для внешних переменных инициализация выполняется только один раз, на этапе компиляции.
#include <iostream.h> int i=0; /* Класс памяти переменной - внешний. */ /* Область действия переменной - все файлы, */ /* содержащие данную программу. Время существо- */ /* вания i=0 - все время выполнения программы. */ void main () { auto int i=1; /* Блок уровня 1 */ /* В блоке 1 область действия i=1 - функция */ /* main(). Время существования i=1 - все время */ /* выполнения главной функции main(). */ cout << i << endl; /* Если две переменные имеют одно и то же имя, */ /* то по этому имени обращаются к внутренней */ /* переменной, внешняя непосредственно недос- */ /* тупна, поэтому после выполнения блока 1 про-*/ /* грамма напечатает 1. */ /* ------------------------------------------- */ cout << ::i << endl; /* При необходимости получить доступ к внешней */ /* переменной используют операцию области ви- */ /* димости. Поэтому здесь будет напечатан 0. */ /* ------------------------------------------- */ { /* Блок уровня 2 */ int i=2; /* Класс памяти переменной i=2 - auto. */ /* Область действия i=2 - блок 2, время */ /* существования - время существования */ /* блока 2. */ cout << i << endl; /* Программа напечатает 2. */ /* ---------------------------------------- */ cout << ::i << endl; /* Тоже будет напечатан 0, так как используя*/ /* операцию области видимости можно получить*/ /* доступ только ко внешней переменной. */ /* -----------------------------------------*/ { /* Блок уровня 3 */ i += 1; cout << i << endl; /* Печатается значение самой внутренней пере- */ /* менной с именем i, которая после выполнения */ /* операции данного блока становится равной 3 */ } /* Возвращение к блоку уровня 2 */ cout << i << endl; /* Опять печатается 3 */ } /* Возвращение к блоку уровня 1 */ cout << i << endl; /* Переменная i=3 из блока уровня 2 исчезает. */ /* Теперь самой внутренней переменной с именем */ /* i будет i=1. */ }
Внешние объекты делятся на внешние глобальные и внешние
статические.
На следующем шаге мы познакомимся с внешними глобальными
объектами.