2012-03-28 2 views
3

У меня есть следующее любопытство включаемых файлов и как они управляются (с GCC):Включите заголовочный файл в C любопытстве

Скажем, у меня есть один исходный файл foo.c и три заголовки Foo. h, foo_cfg.h и foo_int.h.

В foo.c:

#include "foo.h" 
#include "foo_int.h" 

В foo.h:

#include "foo_cfg.h" 

В foo_cfg.h:

/* no inclusions */ 
#define FOO BAR 

В foo_int.h:

/* no inclusions */ 
#define BAR 0U 

Я задаюсь вопросом, почему компиляция завершается успешно. Должен ли файл foo_cfg.h жаловаться, что он не знает о символе BAR?

Кроме того у меня есть еще один исходный файл bar.c, который содержит только файл foo.h и до сих пор работает.

Примечание: это из проекта, над которым я работаю, с сложной средой компоновки, о которой я не нуждаюсь в подробностях. Может ли быть так, что среда сборки влияет на это, кроме указания местоположения для header files?

Возможно, вопрос действительно глупо или я что-то упустил, и приношу свои извинения.

ответ

6

Нет, все в порядке.

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

Далее, при фактической .c файла (вещь, где начинается компиляция) как заголовки включены, так что компилятор видит обе замены: FOO ->BAR и BAR ->0U. Поэтому он успешно применяет оба из них.

Заголовки никогда не компилируются в одиночку, они всегда скомпилированы как часть файла .c, который #include с этим заголовком. (Препроцессор просто притворяется, что содержимое заголовка вставлено в место, где находится #include.) Итак, для препроцессора файл foo.c выглядит следующим образом:

/* no inclusions */ 
#define FOO BAR 
/* no inclusions */ 
#define BAR 0U 
/* the rest of the file... */ 
/* for example: */ 
unsigned int i = FOO; 

И компилятор после предварительной обработки видит только это:

/* no inclusions */ 
/* no inclusions */ 
/* the rest of the file... */ 
/* for example: */ 
unsigned int i = 0U; 

(не совсем уверен, что, может быть, препроцессор удаляет комментарии и .)


Edit:
Действительно, как @pmg упоминает, препроцессор заменяет комментарии с whitespac е, поэтому реальный препроцессором текст, который подается в компилятор просто

_ 
_ 
_ 
_ 
unsigned int i = 0U; 

(здесь _ обозначает пробел)

+0

Теперь я вижу все яснее, спасибо! –

+0

@cilica: добро пожаловать! – Vlad

+1

Вы можете сделать 'gcc -E file.c' для вывода файла после выполнения всей предварительной обработки, хотя это может стать довольно длинным, если вы включите какие-либо стандартные заголовки. – BoBTFish

2

Чтобы продлить ответ Влада немного:

препроцессора макросы расширяются при использовании , а не когда определено.
Итак, когда вы пишете #define FOO BAR, все, что он делает, помнит, что FOO = BAR.
Когда вы пишете #define BAR 0U, он помнит, что BAR = 0U.

Теперь, когда FOO видно в коде, он заменяется BAR, который немедленно заменен 0U.
Порядок, в котором #define FOO и #define BAR появляется в источнике, не имеет значения. Важно то, что когда FOO видно в первый раз, оба определения уже сделаны.

+0

Ahaaa! И поэтому «bar.c» не жалуется на то, что не включен «foo_int.h», потому что на самом деле он не использует ни одного из определений, которые зависят от «foo_int.h». Ну, теперь я просветлен! –