|
^ Blog index    << Preprocesor C - podstawy    >> Preprocesor C - zaawansowane użycie Preprocessor C - szczegóły (preprocesor GNU) 2014-12-17    dr inż. Piotr Romaniuk Spis treści
Argumenty makr Do argumentów makr stosują się następujące reguły:
// Makro z argumentami #define SOME_MACRO( x, y, z) x+y+z // Makro ze zmianna liczbą argumentów #define VAR_ARGS_MACRO(fun,...) fun( __VA_ARGS__ ) // Wywołanie makra bez podania jednego z argumentów #define CALL_FN( fun, arg1 ) fun( arg1 ) CALL_FN( send_char, mychar ); => send_char(mychar); DEV_CTX( get_char,); => get_char(); // Makro z przecinkiem, który nie jest separatorem argumentów makra #define DBG( level, msg_args ) do{\ printf( "<%d> ", level);\ printf msg_args;\ }while[0] DBG( MSG_CRITICAL, ("%s %d", txt, nr) ); // Makro z przecinkiem w argumencie #define CRIT_ENVELOPE( call ) do{ sys_disable_irq();\ call;\ sys_enable_irq();\ }while[0] CRIT_ENVELOPE( get_scheduler_state( &context, &result ) ); Ostatnie dwa powyższe przykłady pokazują jak napisać wieloliniową definicję makra. Poprawia to czytelność kodu, nie ma jednak wpływu na treść makra podczas rozwinięcia - rozwinięcie jest w jednej linii. Podglądając plik pośredni po preprocesingu można zobaczyć: #61 "test.c" do{ sys_disable_irq(); get_scheduler_state( &context, &result ); sys_enable_irq();}while[0]; Komentarza wymaga jeszcze użycie do-while[0] otaczającego całą definicję. Jest to użyte w celu wymuszenia postawienia średnika na końcu użycia makra (będzie omówione w osobnym opisie) Należy zwrócić uwagę, że argumenty pojawiające się w treści makra nie będą rozwinięte jeśli są umieszczone w cudzysłowach. #define SOME_MACRO(x) x, "x" //rozwija się następująco: SOME_MACRO( 123 ) => 123, "x" Jeśli potrzebne jest umieszczenie treści argumentu w stringu należy zastosować operator stringifikacji ##. Gdy preprocesor napotyka na użycie makra, które ma być rozwinięte wykonuje:
#define GET_CHAR_RETTYPE void #define GET_CHAR_FN get_char #define get_char_void sys_get_char(&gctx) #define GET( fn, rtype ) fn ## _ ## rtype GET( GET_CHAR_FN, GET_CHAR_RETTYPE) //rozwinie się do GET_CHAR_FN_GET_CHAR_RETTYPE Aby uzyskać przetwarzanie argumentów należy dodać makro pośredniczące: #define _GET( fn, rtype ) fn ## _ ## rtype #define GET( fn, rtype ) _GET( fn, rtype ) GET( GET_CHAR_FN, GET_CHAR_RETTYPE) //co rozwinie się do: sys_get_char(&gctx) Poniżej przedstawiony jest przykład rekurencji i zachowania preprocesora: #define RECUR( x ) RECUR( x+2 ) // rozwijanie z rekurencją w treści: RECUR( a ) => RECUR( a+2 ) // i w argumencie: RECUR( RECUR( a ) ) => RECUR( RECUR( a+2 )+2 ) Pisząc o traktowaniu spacji należy należy stwierdzić, że nie są one tokenami, tzn. są one sklejane, eliminowane i traktowane w argumentach jedynie jako separatory. #define M( x, y ) fun(x,y) //dla wszystkich poniższych sposobów wykorzystania: M(1,2) M( 1,2) M(1, 2) M(1,2 ) M( 1 , 2 ) M (1,2) //rozwinie się do tego samego, tzn.: fun(1,2) Podobnie są traktowane spacje na liście argumentów w definicji makra: //obie definicje: #define MM_1(x,y) fun(x,y) #define MM_2( x, y ) fun(x,y) MM_1(20,30) MM_2(20,30) //rozwijają się do tego samego: fun(20,30) fun(20,30) Z kolei spacje w treści makra są już kopiowane tak jak są wyszczególnione (wiele spacji jest łączonych w jedną), chyba że sąsiadują z operatorem konkatenacji (łączenia), wtedy są pomijane: #define MM(x,y) fun( x , y) MM(1,2) => fun( 1 , 2) #define MCON(x,y) fun( x ## y ) MCON(a,b) => fun( ab ) Na zakończenie BARDZO WAŻNA uwaga dotycząca spacji w definicji makra umieszczonej pomiędzy nazwą makra a listą argumentów (dokładnie otwierającym nawiasem). Umieszczenie takiej spacji prowadzi do tego, że preprocesor rozpoznaje definicję, jako definicję makra bez parametrów. Następująca po niej (tzn. po nazwie) lista argumentów w nawiasach staje się częscią rozwinięcia, co z kolei powoduje, że zamierzone argumenty nie są rozwijane. // Makro ze zbędną spacją po nazwie - jest interpretowane jako bezargumentowe // a nawias jest uznawany za treśc makra (rozwinięcie) #define MACRO1 (x, y) x+y MACRO1(1,2) // rozwinie się do: (x, y) x+y(1,2)
Linki
|
||||||