В C, как я могу ограничить область действия глобальной переменной файлом, в котором она объявлена? - PullRequest
7 голосов
/ 26 июня 2009

Я новичок в C. У меня перед собой книга, в которой объясняется «область действия» C, включая пример кода. Но код только объявляет и инициализирует переменную области файла - он не проверяет область действия переменной, например, пытаясь получить к ней доступ незаконным способом. Так! В духе науки я построил эксперимент.

Файл bar.c:

static char fileScopedVariable[] = "asdf";

Файл foo.c:

#include <stdio.h>
#include "bar.c"

main()
    {
    printf("%s\n", fileScopedVariable);
    }

Согласно моей книге и Google, звонок на printf() должен завершиться неудачей, но это не так. foo.exe выводит строку «asdf» и завершается нормально. Я бы очень хотел использовать область видимости файлов. Чего мне не хватает?

Ответы [ 4 ]

15 голосов
/ 26 июня 2009

Вы включили bar.c, что приводит к тому, что препроцессор буквально копирует содержимое bar.c в foo.c до того, как его коснется компилятор.

Попробуйте избавиться от включаемого файла, но при этом попросите компилятор скомпилировать оба файла (например, gcc foo.c bar.c) и посмотрите, как он жаловался, как вы ожидаете.

Редактировать: Я полагаю, что основная путаница между компилятором и препроцессором. Правила языка соблюдаются компилятором. Препроцессор запускается перед компилятором и воздействует на те команды с префиксом #. Все, что делает препроцессор - это манипулирование простым текстом. Он не анализирует код и не пытается каким-либо образом интерпретировать его значение. Директива "#include" очень буквальная - она ​​говорит препроцессору "вставить содержимое этого файла сюда". Вот почему вы обычно используете только #include для файлов .h (заголовок) и помещаете только прототипы функций и объявления переменных extern в файлы заголовков. В противном случае вы в конечном итоге будете компилировать одни и те же функции или определять одни и те же переменные несколько раз, что недопустимо.

6 голосов
/ 26 июня 2009

Это вызвано запутанными терминами. file scope в C не означает ограничение привязки идентификатора только к одной единице перевода. Это также не означает, что область действия ограничена одним физическим файлом. Вместо этого file scope означает, что ваш идентификатор является глобальным. Термин file здесь относится к тексту, являющемуся результатом обработки всех #include, #define и других директив препроцессора.

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

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

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

В вашем случае включение bar.c в foo.c вставляет определение fileScopeVariable в компилируемую единицу перевода. Таким образом, это видно в этом блоке.

2 голосов
/ 26 июня 2009

Никогда никогда # не включайте файл .c, как вы делаете там. Язык это позволяет, но C-кодеры просто не делают этого, так что вы запутаете людей, если сделаете это. Скорее всего, включая себя.

«# include» означает «Компилятор, перейдите к этому другому файлу и прикрепите его к началу этого файла перед тем, как начать компилировать мой код».

Однажды я потерял целый день в полной растерянности, потому что один из исходных файлов vxWorks сделал это. Я все еще нахожусь на них из-за этого.

0 голосов
/ 26 июня 2009

Удалить вторую инструкцию включения. Как было сказано выше ...

Перед компиляцией вашего кода компилятор предварительно обрабатывает его. На этом этапе он обрабатывает все инструкции, начинающиеся с '#', например #include, #define и т. Д.

Чтобы увидеть результат этого этапа, вы можете просто запустить 'gcc -E' (если вы используете gcc).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...