4 FUNKCJE I STRUKTURA PROGRAMU
Jeśli wstawiany plik zostanie zmieniony, to naturalnie wszystkie pliki korzystające z niego należy ponownie przetłumaczyć.
Definicja o następującej postaci:
#define nazwa zastępujący-tekst
jest makrodefinicją najprostszego rodzaju: dalsze wystąpienia nazwy będą zastępowane przez ciąg znaków tworzący zastępujący-tekst. Nazwa w #define ma taką samą postać, jak nazwa zmiennej; zastępujący ją tekst jest dowolny. Zwykle tym tekstem jest reszta wiersza, ale długie definicje można kontynuować w następnych wierszach po umieszczeniu na końcu każdego przedłużanego wiersza znaku \. Zasięg nazwy wprowadzanej przez #define rozciąga się od miejsca definicji do końca tłumaczonego pliku źródłowego. Definicja może korzystać z poprzednich definicji. Makrorozwinięć dokonuje się jedynie dla całych jednostek leksykalnych (leksemów) i nie stosuje wewnątrz stałych napisowych ograniczonych cudzysłowami. Jeśli na przykład YES jest tak zdefiniowaną nazwą, to nie zostanie zastąpiona w instrukcji printf(”YES”) ani w zwrocie YESMAN. I i
W ten sposób można definiować dowolne nazwy i zastępować je dowolnym tekstem Na przykład w wierszu
#define forever for (;;) /* pętla nieskończona */
definiuje się nowe słowo forever oznaczające pętlę nieskończoną.
Istnieje także możliwość definiowania makr z argumentami, czyli że zastępujący tekst może być różny dla różnych makrowy wołań. Dla przykładu zdefiniujemy makro o nazwie max:
#define max(A, B) ((A) > (B) ? (A) : (B))
Choć wygląda jak wywołanie funkcji, to jednak wywołanie max powoduje wstawienie rozwiniętego tekstu makra bezpośrednio do tekstu programu. W makrorozwinięć1 każde wystąpienie parametru formalnego (tutaj A lub B) zostanie zastąpione przez ak tualny argument. A zatem wiersz programu:
x = max(p+q, r+s);
zostanie zastąpiony następującym: x = ((p+q) > (r+s) ? (p+q) : (r+s));
4.11 PREPROCESOR JĘZYKA C_____
Tak długo, jak argumenty są traktowane w sposób konsekwentny, makro stosowane dla dowolnych typów danych; nie ma potrzeby podawania różnych definicji max dla różnych typów, jak to jest z funkcjami.
Oglądając dokładnie rozwinięcie makra max, na pewno zauważysz kilka zasadzek. Wyrażenia są obliczane dwukrotnie; będzie źle, jeżeli powodują efekty uboczne, jak operatory zwiększania czy operacje wejścia lub wyjścia. Na przykład w wywołaniu
max(i++, j++) /* ŹLE */
dwukrotnie nastąpi zwiększenie większej wartości. Trochę uwagi należy także poświęcić odpowiedniemu stawianiu nawiasów, by zapewnić poprawną kolejność obliczeń; rozważ, co się stanie, gdy makro
#define square(x) x * x /* ŹLE */
(kwadrat liczby) zostanie wywołane w ten sposób: square(z+1).
Minio wszystko makra są bardzo pożyteczne. Jeden z praktycznych przykładów pochodzi z nagłówka <stdio.h>, w którym getchar i putchar często są definiowane jako makra; tym sposobem unika się narzutów spowodowanych realizacją wywołania funkcji dla każdego przetwarzanego znaku. Także funkcje z nagłówka <ctype.h> są zwykle implementowane jako makra.
Definicję nazwy można skasować za pomocą polecenia #undef, zwykle po to, by zagwarantować, że rzeczywiście oznacza nazwę funkcji, a nie makro:
#undef getchar int getchar(void) (...)
Parametry formalne makra nie są zastępowane w stałych napisowych ograniczonych cudzysłowami. Jeśli jednak nazwę parametru w zastępującym tekście poprzedza znak #, to cała kombinacja (ten znak i nazwa parametru) zostanie rozwinięta w ciąg znaków ograniczony cudzysłowami, gdzie parametr będzie zastąpiony argumentem aktualnym. To zaś można połączyć ze sklejaniem napisów, aby utworzyć, powiedzmy, makro pożyteczne w fazie testowania programu:
#define dprint(expr) printf(#expr ” = %g\n”, expr)
To makro wywołane przykładowo tak: dprint(x/y);
127