Когда раскрывается макрос "__FILE__"?

Я делаю в хедере lib.h

#define TEST __FILE__

а потом в main.cpp:

#include "lib.h"
std::cout << TEST;

И мне печатает имя main.cpp. Я бы ожидал файл lib.h. В каком порядке раскрываются инклюды и прочие макросы?


Ответы (2 шт):

Автор решения: Stanislav Volodarskiy

Макросы раскрываются в момент подстановки. Если бы вы использовали макрос внутри lib.h, вы бы получили ожидаемое:

$ cat temp.h
#define TEST __FILE__

void f() {
    puts(TEST);
}

$ cat temp.c
#include <stdio.h>

#include <temp.h>

void g() {
    puts(TEST);
}

int main() {
    f();
    g();
}

$ gcc -I. temp.c

$ ./a.out
./temp.h
temp.c
→ Ссылка
Автор решения: user7860670

В С/C++ используется простой текстовый препроцессор, производящий подстановку кусков текста. Содержимое исходных файлов для него делится на две категории:

  • Директивы препроцессора - строки с # и до неэкроноированного символа переноса строки. Встречая эти директивы, препроцессор их обрабатывает, модифицируя свое поведение и заменяет. В случае с #include директива будет заменена на содержимое соотв. файла. В случае с #define (и большинством прочих директив) директива заменяется на на пустую строку.
  • Тест программы - все, что не является директивами препроцессора. При обработке текста программы при встрече известного препроцессору токена он заменят этот токен на токены для подстановки. Затем заново обрабатывает текст программы начиная с токлько что подставленных токенов. И повторяет этот процесс, пока в тексте программы больше не останется токенов для замены.

Таким образом, встретив в коде из вопроса:

  1. Препроцессор заменяет директиву #include "lib.h" содержимым файла.
  2. Обрабатывая только что вставленный из заголовочного файла текст, натыкается на директиву #define TEST __FILE__
  3. Запоминает, что при встрече в тексте программы токена TEST его надо будет заменить на токен __FILE__, и заменяет директиву на пустую строку.
  4. Натыкается на токен TEST в тексте main.cpp.
  5. Заменяет TEST на __FILE__ по запомненному ранее правилу.
  6. Обрабатывая только то вставленный текст, натыкается на токен __FILE__.
  7. Заменяет __FILE__ на строковый литерал с именем файла, в котором сейчас происходит подстановка, то бишь на "main.cpp".
→ Ссылка