Включить заголовочный файл в C любопытство - PullRequest
3 голосов
/ 28 марта 2012

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

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

In foo.c :

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

In foo.h :

#include "foo_cfg.h" 

In foo_cfg.h :

/* no inclusions */   
#define FOO BAR

In foo_int.h :

/* no inclusions */ 
#define BAR 0U

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

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

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

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

Ответы [ 2 ]

6 голосов
/ 28 марта 2012

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

Видите ли, препроцессору все равно, определен ли BAR или нет вообще. Он просто заменяет string 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, препроцессор заменяет комментарии пробелами, поэтому реальный предварительно обработанный текст, который передается в компилятор, это просто

_
_
_
_
unsigned int i = 0U;

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

2 голосов
/ 28 марта 2012

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

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

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

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