Standard C określa trzy formy #include
:
#include <file>
#include "file"
#include ANYTHING ELSE
w dawnym dwóch przypadkach nie makro ekspansję ma miejsce, więc nie można zmienić zachowania. W trzecim przypadku, C99 mówi (§6.10.2p4):
The preprocessing tokens after #include
in the directive are [macro-expanded]. The directive resulting after all replacements shall match one of the two previous forms [footnote: Note that adjacent string literals are not concatenated into a single string literal]. The method by which a sequence of preprocessing tokens between a < and a > preprocessing token pair or a pair of " characters is combined into a single header name preprocessing token is implementation-defined.
nieco inny, ale skutecznie równoważne sformułowanie pojawia się w C++ 98 §16.2p4.
Każde zdanie z „powinien” w nakłada twardy warunek: w tym przypadku, program jest źle sformułowane jeśli ANYTHING ELSE
rozszerza się do czegokolwiek, ale sekwencji tokenów zaczynających się <
a kończąc >
lub rozpoczynających i kończących się na "
. Dokładna interpretacja tej sekwencji tokenów to zdefiniowana implementacja, ale zauważmy, że przypis konkretnie zakazuje dosłownego konkatenacji.
Tak, jak ekspansja __FILE__
jest ciągiem stałym, jedyne sposoby, aby używać go w #include
są
#include __FILE__
które, jak odkrył, prowadzi do nieskończonej rekurencji i
#define LT <
#define GT >
#include LT __FILE__ etc GT
który ma zabawne, ale bezużyteczne efekty na wszystkich kompilatorach, które mogę wygodnie przetestować. Zakładając, że powyższe jest w pliku o nazwie test.c
: próby
- GCC, aby otworzyć plik o nazwie
"test.c" etc
z cudzysłowów i miejsca włączone dosłownie.
- clang jest jeszcze bardziej dosłowny i szuka tej samej nazwy pliku, ale z spacji wiodącej i końcowej.
- MSVC makro rozszerza tylko
LT
(to moja opinia uznać, że jest to naruszenie zgodności), skarży się, że nie ma dopasowania >
, a następnie próbuje otworzyć plik o nazwie __FILE__ etc GT
.
(GCC's behavior is documented here, jesteś na własną rękę do niczego innego.)
tl; dr: Nie ma sposobu, aby robić to, co chcesz od wewnątrz preprocesora. Polecam opracowanie nazwy pliku, który ma zostać dołączony do systemu kompilacji i powiadomienie kompilatora o przełączniku -D
(w systemie Unixy potrzebna jest podwójna notacja, -DINCLUDEME='"includeme.h"'
; nie mówię o CMD)
Nie można edytować nazwy pliku, a konkatenacja sąsiednich literałów łańcuchowych występuje w fazie 6 tłumaczenia, ale wstępne przetwarzanie odbywa się w fazie 4, więc nie można używać łączenia ciągów. Oznacza to, że nie można zbudować nazwy pliku, który może być włączony przez preprocesor z '__FILE__'. –