Przyklady:
1)
Preprocesor jest wywoływany w pierwszym kroku tłumacze-
#define YES 1
nia programu; przed rozpocz¸
eciem właściwej kompilacji.
2)
#define then
Preprocesor przetwarza tekst źródłowy progarmu !!!
#define begin
{
Wstawianie plików
#define end
;}
Cz¸
esto na pocz¸
atku programu pojawiaj¸
a si¸
e jeden lub dwa
Nast¸
epnie można pisać:
wiersze postaci:
if (i>0) then
begin
#include <nazwa_pliku>
a=1;
albo
b=2;
#include "nazwa_pliku"
end
Oznaczaj¸
a one,
że w miejscu wyst¸
apienia polecenia inc-
Makro z argumentami
lude zostanie wstawiona zawartość pliku określonego przez nazwa_pliku.
<nazwa_pliku> oznacza, ze plik bedzie poszukiwany zgodnie z
#define identyfikator(lista-identyfikatorow)
\
zasadami obowi¸
azuj¸
acymi w implementacji
ciag-leksemow
"nazwa_pliku" oznacza, że poszukiwanie pliku zaczyna si¸
e tam,
gdzie znaleziono progarm źródłowy, a jeśli w tym miejscu go nie ma, to plik jest poszukiwany zgodnie z zasadami obowi¸
azuj¸
acymi
Przykład:
w implementacji.
Ograniczenia w przypadku użycia pierwszej formy:
#define max(a,b)
((a)>(b)?(a):(b))
• W nazwa_pliku nie może wyst¸apić znak
>
oraz znak
nowego wiersza
Nawiasy w definicji sa istotne, ponieważ np.
• Skutek tej instrukcji jest nieokreślony, jeżeli wyst¸api kt6óryś ze znaków
"
’
\
lub para znaków
/*
.
x=max(p+q,r+s);
zostanie zastapione przez
x=((p+q)>(r+s)?(p+q):(r+s);
Ograniczenia w przypadku użycia drugiej formy:
• skutek użycia znaków
’
\
oraz pary znaków
Kilka reguł:
/*
jest nadal nieokreślony
• definicja może korzystać z poprzednich definicji (zagnież-
• znak
>
jest dozwolony
dżenie),
• makrorozwini¸ecie nie obowi¸azuje w stałych tekstowych Możliwe jest również użycie wiersza postaci: ograniczonych znakami cudzysłowu, np.
printf("YES");
#include ciag_leksemow
nie spowoduje zast¸
apienia YES.
Ci¸
ag leksemów jest rozwijany wówczas zgodnie ze zwykłymi re-gułami, natomiast w wyniku musi doprowadzić do jednej z po-Przykład 2:
staci:
<...> albo
"...".
/*
makro zamieniajace miejscami argumenty */
Stosowanie #include jest zalecanym sposobem sporz¸
adzania
#define SWAP(x,y)
{
\
deklaracji dla dużego programu.
Gwarantuje to identyczność
double tmp;
\
definicji i deklaracji zmiennych i funkcji.
tmp=x;
\
Uwaga: W¸
aczanie plików może być zagnieżdżone.
x=y;
\
y=tmp;
\
Makrorozwini¸
ecia – zast¸
apienie nazwy przez ci¸
ag zna-
}
ków
Zas¸
ego dyrektywy – od miejsca wyst¸
apienia do końca pliku.
Przykład 3:
Wiersz steruj¸
acy o postaci
#define DOPISZ(name,f,thing)
\
{
\
FILE *out;
\
#define identyfikator
ciag-leksemow
out=fopen("a:\\kat\\"#name,"a");\
fprintf(out,f,thing);
\
fclose(out);
\
zleca preprocesorowi zast¸
epowanie dalszych wyst¸
apień identyfi-
}
katora wskazanym ci¸
agiem leksemów. Opuszca si¸
e odst¸
epy ota-
czaj¸
ace ci¸
ag leksemów.
UWAGA: Należy unikać jako argumentów wyrażeń maj¸
acych
Uwaga Ponowne wyst¸
apienie
#define
z tym samym
efekty uboczne, a także wywołań funkcji, ponieważ po roz-identyfikatorem traktuje si¸
e jako błedne, jeżeli ci¸
agi leksemów
wini¸
eciu makrodefinicji tekst może zostać wstawiony kilkakrot-nie s¸
a w obu przypadkach identyczne (przy tym wszystkie białe nie.
plamy rozdzielaj¸
ace leksemy traktuje si¸
e jako równoważne).
Przykłady:
#define max(x,y) ((x)>(y)?(x):(y)) var123
maximum=max(++a,10);
Wynik wywolania
/* wynikiem b\c edzie 10 albo
a+2
*/
/* a bedzie zwiekszone o 1 lub 2
*/
cat(cat(1,2),3)
maximum=max(fgetc(file),maximum);
jest nieokreślony; obecność operatora
##
zapobiega roz-
/* tak mozna sasiada najwiekszego
wini¸
eciu argumentów wewn¸
etrznego wywołania.
znaku w pliku
*/
W rezultacie powstanie
cat( 1 ,2 )3
, w którym lek-
sem
)3
(wynik sklejenia ostatniego leksemu pierwszego ar-maximum=max(rand(),maximum);
gumentu z pierwszym leksemem drugiego jest niepoprawny.
/*
!!!!!!
*/
Po wprowadzeniu makra drugiego poziomu Uwaga: Ostrożnie z używaniem średnika w makrodefinicjach.
#define xcat(x,x) cat(x,y)
Wiersz steruj¸
acy o postaci
wszystko to działa bardziej przyzwoicie: xcat(xcat(1,2),3) rze-
#undef identyfikator
czywiście tworzy leksem 123, ponieważ w samym xcat nie wyst¸
epuje operator
##
.
Podobnie
ABSDIFF(ABSDIFF(a,b),c)
tworzy wynik w
zleca preprocesorowi, aby zapomniał definicj¸
e identyfikatora. Za-
pełni rozwini¸
ety zgodnie z oczekiwaniem.
stosowanie
#undef
do nie zdefiniowanego identyfikatora nie jest bł¸
edem.
Kompilacja warunkowa
Fragmenty programu mog¸
a być kompilowane warunkowo
Znaki
#
i
##
zgodnie z poniższ¸
a schematyczn¸
a składni¸
a:
Jeśli parametr poprzedzany znakiem
#
, to identyfikator
parametru wraz ze znakiem
#
zostan¸
a zast¸
apione odpowied-
nim argumentem otoczonym znakami cudzysłowu " .
Kompilacja warunkowa:
Każdy ze znaków
"
i
\
wyst¸
epuj¸
acy na pocz¸
atku, w
wiersz-if tekst czesci-elif czesc-else
#endif
środku lub na końcu stałych znakowych i napisów tworz¸
acych
argument zostanie poprzedzony znakiem
\
.
wiersz_if:
#if wyrazenie-stale
Jeśli w ci¸
agu leksemów definiuj¸
acych makro wyst¸
api opera-
#ifdef identyfikator
tor
## , to po zast¸
apieniu parametrów napisami – operator
#ifndef identyfikator
## wraz z otaczaj¸
acymi go białymi plamami zostanie usuni¸
ety.
Jeśli tak utworzony leksem jest niepoprawny lub wykonanie czesci el-if:
zależy od kolejności, to skutek jest niezdefiniowany.
wiersz-elif tekst
Niezależnie od postaci makrodefinicji zast¸
epuj¸
acy ci¸
ag lek-
czesci-elif
semów jest wielokrotnie przegl¸
adany w poszukiwaniu innych
tak zdefiniowanych identyfikatorów. Jeżeli jednak identyfikator wiersz-elif:
zast¸
apiony już w danym rozwini¸
eciu, znów pojawi si¸
e przy po-
#elif wyrazenie stale
nownym przegl¸
adaniu, to pozostanie w rozwini¸
etym tekście bez
zmiany.
czesc-else
Mechanizm makrodefinicji przydaje si¸
e do definiowania
wiersz_else tekst
”wżnych stałych
Przykład:
czesc-else:
wiersz-else tekst
#define ABSDIFF(a,b)
((a)>(b)?(a)-(b):(b)-(a))
wiersz-else:
#else
Definiuje makro zwracaj¸
ace wartość absolutn¸
a różnicy jego ar-
gumentów.
W przeciwieństwie do funkcji zwracana wartość może być dowol-Kilka reguł:
nego typu.
• Wyrażenia stałe wyst¸epuj¸ace w
#if
i
#elif
s¸
a ob-
liczane kolejno, aż do wyst¸
apienia wyrażenia z niezerow¸
a
#define tempfile(dir) #dir "/%s"
wartości¸
a.
• Tekst nast¸epuj¸acy po wyrażeniach z zerow¸a wartości¸a Wywołanie
tempfile(/usr/tmp)
daje w wy-
opuszcza si¸
e w czasie kompilacji.
niku
• Tekst wyst¸epuj¸acy po wyrażeniach z pozytywn¸a wartości¸a jest wł¸
aczany do programu.
"/usr/tmp" "/%s"
• Po znalezieniu wyrażenia z pozytywn¸a wartości¸a i jego ob-służeniu to kolejne wiersze #elif
lub #else
s¸
a po-
co nast¸
epnie zostaje sklejone w jeden napis. Przy definicji mijane wraz z ich tekstami.
#define cat(x,y)
x ## y
• Jeżeli wszystkie wyrażenia s¸a równe zero i wyst¸epuje
#else
,
to
obsługuje
si¸
e
tekst
nast¸
epuj¸
acy
po
Wywolanie
#else
.
cat(var,123)
• Tekst wyst¸epuj¸acy w gał¸eziach nieaktywnych jest ignoro-wany, ale sprawdza si¸
e najpierw, czy nie wyst¸
epuj¸
a w nim
produkuje leksem
zagnieżdżone konstrukcje warunkowe.
Wyrzżenia stałe w
#if
i
#elif
s¸
a przedmiotem zwy-
zleca kompilatorowi, aby dla celów diagnostycznych przyj¸
ał, że
kłych makrorozwini¸
eć.
nast¸
epny wiersz źródłowy b¸
edzie miał numer okreĺony przez
Wyrażenia postaci:
stał¸
a, a nazw¸
a bież¸
acego pliku źródłowego b¸
edzie nazwa-pliku.
Makra wyst¸
epuj¸
ace w takich wierszach s¸
a rozwijane przed
interpretacj¸
a instrukcji.
defined identyfikator
lub
Generowanie bł¸
edów
defined ( identyfikator )
Wiersz steruj¸
acy o postaci
przed rozwijanie makr otrzymuj¸
a wartość:
#error ciag-leksemow
1L - jeśli identyfikator jest zdefiniowany w preprocesorze zleca procesorowi wypisanie komunikatu diagnostycznego zawie-0L - jeśli nie jest zdefiniowany
raj¸
acego podany ci¸
ag leksemów.
Wszystkie
identyfikatory pozostałe po
makrorozwini¸
eciach
Instrukcja pragma
otrzymuj¸
a wartość
0L
, a cała arytmetyka na stałych jest
przeprowadzana na liczbach całkowitych długich lub długich bez Wiersz steruj¸
acy o postaci
znaku.
Wynikowe wyrażenie stałe ma ograniczenia:
#pragma ciag-leksemow
• musi być całkowite
• nie może zawierać operatora sizeof, rzutowania i stałych zleca procesorowi podj¸ecie akcji zależnej od implementacji. Nie-wyliczeń.
znana akcja jest ignorowana.
Pusta instrukcja preprocesora
Wiersze steruj¸
ace postaci:
Wiersz zawieraj¸
acy jedynie znak
#
nie ma żadnego
skutku.
#ifdef identyfikator
Nazwy zdefiniowane w preprocesorze
#indef identyfikator
Definicji
tych
nazw,
jak
rówmież
operatora
defined
(wyst¸
epuj¸
acego w wyrażeniach preprocesora), nie można odwo-s¸
a równoważne:
łać ani zmienić.
•
LINE
– Dziesi¸
etna stała całkowita zawieraj¸
aca numer
#if defined identyfikator
bież¸
acego wiersza programu źródłowego
#if ! defined identyfikator
•
FILE
– Stała napisowa zawieraj¸
aca nazw¸
e tłumaczo-
nego pliku
Przykłady:
•
DATE
– Stała napisowa zawieraj¸
aca dat¸
e tłumaczenia
1)
/* Kompilowanie programu w kilku wersjach
*/
programu w formacie – "Mmm dd rrrr"
#define DEMO
•
TIME
– Stała napisowa zawierajça czas tłumaczenia
#ifdef DEMO
programu w formacie – "gg:mm:ss"
/*
kod tylko dla wersji demonstracyjnej
*/
•
STDC
– Stała 1. Z zamierzenia identyfikator ten po-instrukcje
winien być zdefiniowany z wartości¸
a 1 jedynie w imple-
mentacjach dostosowanych do standardu.
#endif
#ifndef DEMO
/*
Kod tylko dla wersji normalnej
*/
#endif
2)
/*
Uniemozliwienie wielokrotnego przetwarzania tego samego kodu zrodlowego
*/
/*
poczatek pliku naglowkowego
okienka.h
*/
#ifndef OKIENKA
#define OKIENKA
/*
tresc pliku
*/
#endif
/*
Koniec pliku okienka
*/
Numeracja wierszy
Dla potrzeb innych preprocesorów, które generuj¸
a programy
w j¸
ezyku C, wiersz maj¸
acy jedn¸
a z postaci
#line stala "nazwa-pliku"
#line stala