Więcej o firmie ELESOFTROM

Firma ELESOFTROM specjalizuje się w wykonywaniu i naprawianiu oprogramowania dla sterowników mikroprocesorowych.

Posiadamy ponad 10-letnie doświadczenie w tej dziedzinie.

W realizowanych projektach stawiamy na niezawodność i wydajność programów.

Naprawa oprogramowania

Oprogramowanie na zamówienie


Strona główna

Pełna oferta

Doświadczenie

O firmie

Kontakt


DioneOS - RTOS dla urządzeń embedded

Firma ELESOFTROM opracowała system RTOS dla procesorów ARM Cortex-M3 oraz msp430.

System jest zoptymalizowany pod względem wydajności, dzięki czemu uzyskano krótki czas przełączania pomiędzy wątkami.
System dostarcza elementy (np. semafory, mutexy, timery, kolejki itp.) niezbędne do tworzenia wielowątkowego firmware'u.

Wersja dla Cortexa została całkowicie przetestowana przy pomocy środowiska do automatycznego testowania.

Przeczytaj więcej:

Strona o systemie DioneOS

Niezawodność

Wydajność

Dokumentacja DioneOSa

Prezentacje n.t. DioneOS


^ 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
Kolejność przetwarzania
Spacje
Preprocesor - podstawy (osobny wpis)
Preprocesor - zaawansowane wykorzystanie (osobny wpis)

Argumenty makr

Do argumentów makr stosują się następujące reguły:

  • Argumenty są rodzielane przecinkami
  • Lista argumentów jest podana w nawiasach okrągłych.
  • Liczba nawiasów otwierających i zamykających musi się zgadzać.
  • Liczba podanych argumentów makra musi się zgadzać z definicją (szczególnym przypadkiem jest zmienna liczba argumentów).
  • Jeśli jako argument wykorzytuje się jakiś fragment zawierający przecinek, to aby nie był interpretowany jako separator argumentów makra, to trzeba ten fragment trzeba objąć nawiasami okrągłymi.
  • Argument może być pusty (tzn. nie podany).
// 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 ##.

Kolejność przetwarzania

Gdy preprocesor napotyka na użycie makra, które ma być rozwinięte wykonuje:

  • wstępne przeglądanie (prescan) podczas, którego rozwija wszystkie argumenty
  • po zastąpieniu ich wystąpień w treści makra powtórnie ją skanuje w celu rozwinięcia innych makr, które tam mogą się pojawić
  • argumenty nie są przetwarzane (rozwijane) gdy będą stringifikowane lub poddane konkatenacji
  • preprocesor unika rekurencji - w treści makra nie jest rozwijana nazwa przetwarzanego makra
#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 )

Spacje

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

  1. Dokumentacja preprocesora na stronach gcc/GNU
  2. Opis makrodefinicji
  3. Opis dotyczący argumentów makr
  4. Kolejność przetwarzania i wstępne przeglądanie i rozwijanie argumentów