Dlaczego potrzebuję podwójnej warstwy indrection dla makr?
Czy ktoś mógłby mi wyjaśnić dlaczego ? Wszystko co czytam to zaufaj mi , ale po prostu nie mogę ufać w coś, bo ktoś tak powiedział.
Próbowałem podejścia i nie mogę znaleźć żadnych błędów pojawiających się:
#define mymacro(a) int a ## __LINE__
mymacro(prefix) = 5;
mymacro(__LINE__) = 5;
int test = prefix__LINE__*__LINE____LINE__; // fine
Więc dlaczego Czy muszę to robić w ten sposób (cytat ze strony):
Jednak potrzebujesz podwójnej warstwy indrection, gdy używasz ##. Zasadniczo musisz utworzyć specjalne makro do "wklejania tokenów" takie as:
#define NAME2(a,b) NAME2_HIDDEN(a,b) #define NAME2_HIDDEN(a,b) a ## b
Zaufaj mi - naprawdę musisz to zrobić to! (I proszę niech nikt mi nie pisze, że czasami działa bez druga warstwa indrection. Spróbuj połączyć symbol z __ LINE _ _ i zobaczyć, co się wtedy stanie.)
Edit: Czy ktoś mógłby też wyjaśnić dlaczego używa NAME2_HIDDEN
zanim zostanie to zadeklarowane poniżej? Informatyka bardziej logiczne wydaje się zdefiniowanie makra NAME2_HIDDEN
zanim go użyję. To jakaś sztuczka?
5 answers
Odpowiednia część C spec:
6.10.3.1 podstawienie argumentu
Po zidentyfikowaniu argumentów wywołania makra podobnego do funkcji, następuje podstawienie argumentu. Parametr na liście zastępczej, chyba że poprzedzony przez # lub # # Token wstępnego przetwarzania lub po nim # # Token wstępnego przetwarzania (patrz poniżej), jest zastąpiony przez odpowiedni argument po tym, jak wszystkie makra w nim zawarte zostały Rozszerzony. Przed byciem podstawione, tokeny wstępnego przetwarzania każdego argumentu są całkowicie makro zastąpione tak, jakby tworzyły resztę pliku wstępnego przetwarzania; żadne inne dostępne są tokeny wstępnego przetwarzania.
Kluczową częścią, która określa, czy chcesz mieć podwójną indrection, czy nie, jest drugie zdanie i wyjątek w nim -- jeśli parametr jest zaangażowany w operację #
lub ##
(np. params w mymacro
i NAME2_HIDDEN
), to żadne inne makra w argumencie nie są rozwijane przed robi #
LUB ##
. Jeśli natomiast w ciele makra nie ma #
lub ##
bezpośrednio (jak w przypadku NAME2
), to inne makra w parametrach są rozszerzane.
Więc sprowadza się do tego, co chcesz-czasami chcesz, aby wszystkie makra zostały najpierw rozbudowane, a następnie wykonać #
LUB ##
(w tym przypadku chcesz dwuwarstwową indirection), a czasami nie chcesz, aby makra zostały najpierw rozbudowane (w tym przypadku nie możesz mieć dwuwarstwowych makr, musisz to zrobić bezpośrednio.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-28 17:56:39
__LINE__
jest specjalnym makrem, które ma rozwiązać do bieżącego numeru linii. Jeśli jednak wykonasz wklejenie tokenu za pomocą __LINE__
bezpośrednio, nie ma to szansy na rozwiązanie, więc kończysz z tokenem prefix__LINE__
zamiast, powiedzmy, prefix23
, Jak prawdopodobnie spodziewałbyś się, gdybyś napisał ten kod w dziczy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 18:43:14
Chris Dodd ma doskonałe wyjaśnienie pierwszej części twojego pytania. Jeśli chodzi o drugą część, dotyczącą sekwencji definicji, skrócona wersja jest taka, że dyrektywy #define
same w sobie nie są w ogóle oceniane; są one oceniane i rozszerzane tylko wtedy, gdy symbol znajduje się w innym miejscu Pliku. Na przykład:
#define A a //adds A->a to the symbol table
#define B b //adds B->b to the symbol table
int A;
#undef A //removes A->a from the symbol table
#define A B //adds A->B to the symbol table
int A;
Pierwszy int A;
staje się int a;
, ponieważ tak definiuje się A
w tym punkcie pliku. Drugi int A;
staje się int b;
po dwóch rozszerzeniach. On najpierw rozszerzony do int B;
, ponieważ A
jest zdefiniowany jako B
w tym momencie pliku. Następnie preprocesor rozpoznaje, że B
jest makrem, gdy sprawdza tabelę symboli. {[9] } jest następnie rozszerzony do b
.
Jedyną rzeczą, która się liczy, jest definicja symbolu w punkcie ekspansji, niezależnie od tego, gdzie jest definicja.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 20:07:37
Kolejność deklarowania makr nie jest ważna, kolejność ich użycia jest. Gdybyś faktycznie użył tego makra zanim zostało ono zadeklarowane -- (w rzeczywistym kodzie, czyli nie w makrze, które pozostaje uśpione do momentu wywołania) wtedy dostałbyś błąd, ale ponieważ większość zdrowych ludzi nie robi tego rodzaju rzeczy, pisząc makro, a następnie pisząc funkcję, która używa makra jeszcze nie zdefiniowanego w dół, itd., itp... Wygląda na to, że twoje pytanie nie jest tylko jednym pytanie, ale odpowiem tylko na jedną część. Myślę, że powinieneś to jeszcze bardziej rozłożyć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-15 09:11:10
Najbardziej nietechniczna odpowiedź, którą zebrałem ze wszystkich linków tutaj, i link linków;) jest taka, że jednowarstwowa indrection macro(x) #x
stringifies nazwa wprowadzonego makra, ale używając podwójnych warstw, będzie to stringify wartość wprowadzonego makra.
#define valueOfPi 3
#define macroHlp(x) #x
#define macro(x) macroHlp(x)
#define myVarOneLayer "Apprx. value of pi = " macroHlp(valueOfPi)
#define myVarTwoLayers "Apprx. value of pi = " macro(valueOfPi)
printf(myVarOneLayer); // out: Apprx. value of pi = valueOfPi
printf(myVarOTwoLayers); // out: Apprx. value of pi = 3
Co się dzieje w printf(myVarOneLayer)
printf(myVarOneLayer)
jest rozszerzony do printf("Apprx. value of pi = " macroHlp(valueOfPi))
macroHlp(valueOfPi)
próbuje przeciągnąć dane wejściowe, samo dane wejściowe nie są oceniane. Jedynym celem w życiu jest wzięcie udziału i naciągnięcie. Więc rozszerza się na "valueOfPi"
Więc, co się dzieje w printf(myVarTwoLayers)
printf(myVarTwoLayers)
jest rozszerzony do printf("Apprx. value of pi = " macro(valueOfPi)
macro(valueOfPi)
nie ma operacji stringification, tzn. nie ma #x
w jego rozszerzeniu, ale jest x
, więc musi ocenić x
i wprowadzić wartość do macroHlp
dla stringification. Rozszerza się do macroHlp(3)
, co z kolei będzie ciągiem liczby 3, ponieważ używa #x
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-08 21:55:12