netlib.narod.ru< Назад | Оглавление | Далее >

4.4. Области видимости

Нет никакой необходимости каждый раз компилировать все функции и внешние переменные, из которых состоит программа на Си. Исходный текст программы может храниться в нескольких файлах, а ранее скомпилированные подпрограммы можно загружать из библиотек. В связи с этим возникают следующие вопросы:

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

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

Область видимости внешней переменной или функции простирается от точки программы, где она объявлена, до конца компилируемого файла. Например, если main, sp, val, push и pop определены в одном файле в следующем порядке

    main() { ... }

    int sp = 0;
    double val[MAXVAL];

    void push(double f) { ... }
    double pop(void) { ... }

то из функций push и pop к переменным sp и val можно обращаться просто по их именам; никаких дополнительных объявлений для этого не требуется. Заметим, что из функции main эти имена и сами функции push и pop не видимы.

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

Важно отличать объявление (declaration) внешней переменной от ее определения (definition). Объявление описывает свойства переменной (прежде всего ее тип), а определение, кроме того, приводит к выделению для нее памяти. Строки

    int sp;
    double val[MAXVAL];

расположенные вне всех функций, определяют внешние переменные sp и val, т.е. отводят для них память, и, кроме того, служат объявлениями для остальной части исходного файла. А вот строки

    extern int sp;
    extern double val[];

объявляют для оставшейся части файла, что sp — переменная типа int, а val — массив типа double (размер которого определен где-то в другом месте); при этом ни переменная, ни массив не создаются, и память для них не выделяется.

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

Инициализировать внешнюю переменную можно только в определении.

Хотя вряд ли стоит организовывать нашу программу таким образом, но мы определим push и pop в одном файле, а val и sp — в другом, где их и инициализируем. При этом для установления связей потребуются следующие определения и объявления:


В файле 1:

    extern int sp;
    extern double val[];

    void push(double f) { ... }

    double pop(void) { ... }

В файле 2:

    int sp = 0;
    double val[MAXVAL];

Поскольку объявления extern находятся в начале файла 1 и вне определений функций, их действие распространяется на все функции, причем одного набора объявлений достаточно для всего файла 1. Та же организация объявлений extern необходима и в случае, когда программа состоит из одного файла, но определения sp и val расположены после их использования.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz