#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
Czy można łączyć, że STR3 == "s1"? Możesz to zrobić, przekazując argumenty do innej funkcji Macro. Ale czy istnieje bezpośredni sposób?
#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
Czy można łączyć, że STR3 == "s1"? Możesz to zrobić, przekazując argumenty do innej funkcji Macro. Ale czy istnieje bezpośredni sposób?
Odpowiedzi:
Jeśli to oba ciągi, możesz po prostu zrobić:
#define STR3 STR1 STR2
Preprocesor automatycznie łączy sąsiednie ciągi.
EDYTOWAĆ:
Jak zauważono poniżej, to nie preprocesor, ale kompilator wykonuje konkatenację.
L"a"
i "b"
dostać L"ab"
, ale można złączyć L"a"
i L"b"
dostać L"ab"
.
Nie potrzebujesz tego rodzaju rozwiązania dla literałów łańcuchowych, ponieważ są one konkatenowane na poziomie języka, a i tak by nie zadziałało, ponieważ „s” „1” nie jest prawidłowym tokenem preprocesora.
[Edytuj: W odpowiedzi na niepoprawny komentarz "Tylko do zapisu" poniżej, który niestety otrzymał kilka głosów za, powtórzę powyższe stwierdzenie i zauważę, że fragment programu
#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")
generuje ten komunikat o błędzie z fazy przetwarzania wstępnego gcc: błąd: wklejanie "" s "" i "1" "nie daje prawidłowego tokena przetwarzania wstępnego
]
Jednak w przypadku ogólnego wklejania tokenów spróbuj tego:
/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B
/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)
Następnie, na przykład, oba PPCAT_NX(s, 1)
i PPCAT(s, 1)
produkują identyfikator s1
, chyba że s
jest zdefiniowane jako makro, w którym to przypadku PPCAT(s, 1)
produkuje <macro value of s>1
.
Kontynuacją tematu są te makra:
/*
* Turn A into a string literal without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define STRINGIZE_NX(A) #A
/*
* Turn A into a string literal after macro-expanding it.
*/
#define STRINGIZE(A) STRINGIZE_NX(A)
Następnie,
#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"
Natomiast
STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"
#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
"s""1"
obowiązuje w C (i C ++). Są to dwa tokeny (literały ciągów), które kompilator połączy ze sobą i zagrozi jako jeden token.
"s""1" isn't a valid token
- to jest poprawne; są to, jak mówisz, dwa żetony. Ale połączenie ich razem z ## uczyniłoby je pojedynczym tokenem przetwarzania wstępnego, a nie dwoma, więc kompilator nie wykonałby konkatenacji, a lekser odrzuciłby je (język wymaga diagnostyki).
STRINGIZE_NX(whatever occurs here)
Rozwija się więc do „cokolwiek tu się dzieje”, niezależnie od jakichkolwiek makdefinicji tego, co się dzieje, lub tutaj.
if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED"
- to nieprawda i w niczym nie przypomina twojego testu. Bardzo starasz się nie zrozumieć lub nie zrobić tego dobrze, i nie zamierzam ci dalej odpowiadać.
Wskazówka: STRINGIZE
powyższe makro jest fajne, ale jeśli popełnisz błąd i jego argument nie jest makrem - miałeś literówkę w nazwie lub zapomniałeś #include
pliku nagłówkowego - kompilator szczęśliwie umieści rzekomą nazwę makra w ciąg bez błędu.
Jeśli zamierzasz, aby argumentem STRINGIZE
zawsze było makro z normalną wartością C, to
#define STRINGIZE(A) ((A),STRINGIZE_NX(A))
rozwinie go raz i sprawdzi, czy jest poprawny, odrzuci to, a następnie ponownie przekształci w łańcuch.
Zajęło mi trochę czasu, zanim zrozumiałem , dlaczego STRINGIZE(ENOENT)
skończyło się na tym, że "ENOENT"
zamiast "2"
… nie uwzględniłem errno.h
.
,
operatora. :)
((1),"1") "." ((2),"2")
zamiast „1” ”.„ „2”)
STRINGIZE
definicją "The value of ENOENT is " STRINGIZE(ENOENT)
działa, podczas gdy "The value of ENOENT is" STRINGIZE_EXPR(X)
powoduje błąd.