#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 sjest 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: STRINGIZEpowyż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ś #includepliku nagłówkowego - kompilator szczęśliwie umieści rzekomą nazwę makra w ciąg bez błędu.
Jeśli zamierzasz, aby argumentem STRINGIZEzawsze 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”)
STRINGIZEdefinicją "The value of ENOENT is " STRINGIZE(ENOENT)działa, podczas gdy "The value of ENOENT is" STRINGIZE_EXPR(X)powoduje błąd.