Prawo Murphy'ego: Wniosek to punkt, w którym nie masz już siły dalej myśleć.
C++: Dyrektywy preprocesora
Włączanie plików - dyrektywa #include

Dyrektywa #include ma jedną z 2 postaci:

#define <nazwa_pliku>
lub
#define "nazwa_pliku"

Dyrektywa #include służy do włączania pliku o podanej nazwie do kompilowanego programu.
W pierwszej postaci plik o podanej nazwie jest poszukiwany w katalogach systemowych kompilatora.
W drugiej postaci plik jest najpierw poszukiwany w katalogu bieżącym (tym, w którym zapisany jest kompilowany program). Jeśli tam nie zostanie znaleziony to poszukiwanie jest kontynuowane tak samo, jak w pierwszej postaci, czyli w katalogach systemowych kompilatora.

Makrodefinicje - dyrektywa #define

Do tworzenia makrodefinicji służy dyrektywa #define. Składnia:

#define identyfikator ciąg_symboli
lub
#define identyfikator(id1, id2, ...) ciąg_symboli

Pierwsza postać zleca preprocesorowi zastąpienie każdego wystąpienia identyfikatora wskazanym ciągiem_symboli. Spacje rozpoczynające i kończące ciąg_symboli są usuwane.

Przykład:
   #define WIERSZY 10
   #define KOLUMN 5
   ...
   int tablica[WIERSZY][KOLUMN];
deklaracja tablicy tablica zostanie zamieniona w następujący sposób:
int tablica[10][5];

Druga postać dyrektywy #define służy do definicji tzw. makra funkcyjnego. W tej dyrektywie pomiędzy identyfikatorem i nawiasem otwierającym ( nie może być spacji. W programie każde wystąpienie identyfikatora, po którym następuje nawias oraz ciągi identyfikatorów oddzielone przecinkami i zakończone nawiasem zamykającym są traktowane jako makrodefinicje. Makrodefinicje zastępuje się ciągiem_symboli podanym w makrodefinicji. Spacje rozpoczynające i kończące ciąg_symboli są usuwane. W podanym ciągu każde wystąpienie identyfikatora z listy parametrów (id1, id2, ...) zastępuje się parametrami aktualnego makrowywołania. Liczba parametrów w makrodefinicji musi być taka sama, jak w makrowywołaniu.

Przykład:
   #define MIN(x, y) (((x) < (y)) ? (x) : (y))
   ...
   a = MIN(i, j);
przypisanie zostanie zastąpione przez:
   a = (((i) < (j)) ? (i) : (j);

Przy definiowaniu makrodefinicji funkcyjnych należy wszystkie argumenty ujmować w nawiasy - makrodefinicje są rozwijane tekstowo przez preprocesor, co może powodować nieoczekiwaną zmianę znaczenia pewnych zapisów, jak np.:

   #define SQR(x) x*x
   ...
   res = SQR(a+4);
spowoduje rozwinięcie do postaci:
   res = a+4*a+4;
podczas, gdy my byśmy oczekiwali, że otrzymamy wyrażenie:
   res = (a+4)*(a+4);

Uwagi:

  1. Panuje konwencja pisania identyfikatorów w makrodefinicjach wielkimi literami.
  2. W rozwiniętym makrowywołaniu poszukiwane są kolejne identyfikatorów do rozwinięcia.
  3. Nie jest możliwe rozwinięcia rekurencyjne.
  4. Nie jest możliwe potraktowanie rozwiniętego tekstu jako nowej dyrektywy preprocesora.
Dyrektywa #undef

Dyrektywa #undef służy do unieważniania wcześniej zdefiniowanego makra. Składnia:

#undef identyfikator
Kompilacja warunkowa - #if, #elif, #else, #endif

Jeżeli istnieje konieczność warunkowej kompilacji fragmentów programu, to możemy do tego celu użyć jednej z poniższych składni:

#if defined(nazwa)
... // kod programu kompilowany, gdy zdefiniowano symbol nazwa
[ #elif defined (nazwa1) ]
... // kod programu kompilowany, gdy zdefiniowano symbol nazwa1
[ #else ]
... // kod programu kompilowany, gdy nie zdefiniowano symboli nazwa ani nazwa1
#endif
lub
#ifdef nazwa
... // kod programu kompilowany, gdy zdefiniowano symbol nazwa
[ #else ]
... // kod programu kompilowany, gdy nie zdefiniowano symbolu nazwa
#endif
lub
#ifndef nazwa
... // kod programu kompilowany, gdy nie zdefiniowano symbolu nazwa
[ #else ]
... // kod programu kompilowany, gdy zdefiniowano symbol nazwa
#endif

Dyrektywy #elif i #else są we wszystkich przypadkach opcjonalne.
W dyrektywach #if, #elif, #ifdef i #ifndef muszą występować wyrażenia stałe (takie, których wartość jest znana podczas kompilacji).
Odpowiedni fragment kodu jest włączany do kompilowanego programu lub nie w zależności od tego czy prawdziwy jest podany warunek, czy nie.

Przykłady:

Różny sposób znalezienia minimalnej wartości w zależności od tego, czy zdefiniowano symbol MIN, czy nie:
   #ifdef MIN
      a = MIN(i, j);
   #else
      a = (i < j) ? (i) : (j);
   #endif
W zależności od zdefiniowanego symbolu dołączane są różne pliki nagłówkowe do obsługi grafiki:
   #if defined(MSC)
      #include <graph.h>
   #elif defined(TURBOC)
      #include <graphics.h>
   #endi
Predefiniowane makra
Pewne makra są zdefiniowane przez kompilator i mogą być używane podczas kompilacji:
__LINE__ stała dziesiętna zawierająca nr bieżącego wiersza pliku źródłowego
__FILE__ stała tekstowa zawierająca nazwę kompilowanego pliku
__DATE__ data kompilacji jako tekst w postaci: Mmm d rrrr
__TIME__ czas kompilacji jako tekst w postaci: gg:mm:ss
__cplusplus oznacza kompilację w standardzie C++
Oprócz podanych wyżej predefiniowanych makr występujących w każdym kompilatorze, niektóre kompilatory mogą predefiniować swoje własne specyficzne makra. Ich spis oraz znaczenie jest opisane w dokumentacji takiego kompilatora.

 

« wstecz   dalej »