dyrektywa #define (C/C++)
#define tworzy makro, które jest skojarzeniem identyfikatora lub identyfikatora sparametryzowanego z ciągiem tokenu. Po zdefiniowaniu makra kompilator może zastąpić ciąg tokenu dla każdego wystąpienia identyfikatora w pliku źródłowym.
Składnia
#define identyfikator token-string opt
#define identyfikator ( identyfikatoropt, ... , identyfikatoropt ) token-stringopt
Uwagi
Dyrektywa #define powoduje, że kompilator zastąpi ciąg token-string dla każdego wystąpienia identyfikatora w pliku źródłowym. Identyfikator jest zastępowany tylko wtedy, gdy tworzy token. Oznacza to, że identyfikator nie jest zastępowany, jeśli pojawia się w komentarzu, w ciągu lub w ramach dłuższego identyfikatora. Aby uzyskać więcej informacji, zobacz Tokeny.
Argument token-string składa się z serii tokenów, takich jak słowa kluczowe, stałe lub pełne instrukcje. Co najmniej jeden znak odstępu musi oddzielić ciąg tokenu od identyfikatora. Ten biały znak nie jest traktowany jako część tekstu zastępczego ani nie jest znakiem odstępu, który następuje po ostatnim tokenie tekstu.
Obiekt #define
bez ciągu tokenu usuwa wystąpienia identyfikatora z pliku źródłowego. Identyfikator pozostaje zdefiniowany i można go przetestować przy użyciu #if defined
dyrektyw i #ifdef
.
Drugi formularz składni definiuje makro podobne do funkcji z parametrami. Ten formularz akceptuje opcjonalną listę parametrów, które muszą pojawić się w nawiasach. Po zdefiniowaniu makra każde kolejne wystąpienie identyfikatora( identyfikatoropt, ..., identyfikatoropt ) jest zastępowane wersją argumentu ciągu tokenu, który ma rzeczywiste argumenty zastąpione parametrami formalnymi.
Formalne nazwy parametrów są wyświetlane w ciągu tokenu, aby oznaczyć lokalizacje, w których są zastępowane rzeczywiste wartości. Każda nazwa parametru może pojawiać się wiele razy w ciągu tokenu, a nazwy mogą być wyświetlane w dowolnej kolejności. Liczba argumentów w wywołaniu musi być zgodna z liczbą parametrów w definicji makra. Liberalne użycie nawiasów gwarantuje, że złożone rzeczywiste argumenty są prawidłowo interpretowane.
Parametry formalne na liście są rozdzielane przecinkami. Każda nazwa na liście musi być unikatowa, a lista musi być ujęta w nawiasy. Żadne spacje nie mogą oddzielić identyfikatora i nawiasu otwierającego. Użyj łączenia linii — umieść ukośnik odwrotny (\
) bezpośrednio przed znakiem nowego wiersza — w przypadku długich dyrektyw w wielu wierszach źródłowych. Zakres formalnej nazwy parametru rozciąga się na nowy wiersz, który kończy ciąg token-string.
Gdy makro zostało zdefiniowane w drugim formularzu składni, kolejne wystąpienia tekstowe, a następnie lista argumentów wskazuje wywołanie makra. Rzeczywiste argumenty, które następują po wystąpieniu identyfikatora w pliku źródłowym, są dopasowywane do odpowiednich parametrów formalnych w definicji makra. Każdy parametr formalny w ciągu tokenu, który nie jest poprzedzony ciągami (#
), charizing (#@
) lub token-pasting (##
) operator, a po którym nie następuje operator, jest zastępowany ##
przez odpowiadający rzeczywisty argument. Wszystkie makra w rzeczywistym argumencie są rozszerzane przed zastąpieniem parametru formalnego przez dyrektywę. (Operatory są opisane w temacie Operatory preprocesora).
Następujące przykłady makr z argumentami ilustrują drugą formę składni #define :
// Macro to define cursor lines
#define CURSOR(top, bottom) (((top) << 8) | (bottom))
// Macro to get a random integer with a specified range
#define getrandom(min, max) \
((rand()%(int)(((max) + 1)-(min)))+ (min))
Argumenty z efektami ubocznymi czasami powodują, że makra generują nieoczekiwane wyniki. Dany parametr formalny może pojawić się więcej niż jeden raz w ciągu tokenu. Jeśli ten parametr formalny jest zastępowany przez wyrażenie z efektami ubocznymi, wyrażenie, z jego efektami ubocznymi, może być oceniane więcej niż raz. (Zobacz przykłady w obszarze Operator wklejania tokenów (##)).
Dyrektywa #undef
powoduje zapomnienie definicji preprocesora identyfikatora. Aby uzyskać więcej informacji, zobacz dyrektywę #undef.
Jeśli nazwa zdefiniowanego makra występuje w ciągu tokenu (nawet w wyniku innego rozszerzenia makra), nie jest rozszerzana.
Druga #define dla makra o tej samej nazwie generuje ostrzeżenie, chyba że druga sekwencja tokenu jest identyczna z pierwszą.
Specyficzne dla firmy Microsoft
Microsoft C/C++ umożliwia ponowne zdefiniowanie makra, jeśli nowa definicja jest składniowo identyczna z oryginalną definicją. Innymi słowy, dwie definicje mogą mieć różne nazwy parametrów. To zachowanie różni się od ANSI C, co wymaga, aby dwie definicje były identyczne leksykalnie.
Na przykład następujące dwa makra są identyczne z wyjątkiem nazw parametrów. Język ANSI C nie zezwala na takie ponowne zdefiniowanie, ale firma Microsoft C/C++ kompiluje go bez błędu.
#define multiply( f1, f2 ) ( f1 * f2 )
#define multiply( a1, a2 ) ( a1 * a2 )
Z drugiej strony następujące dwa makra nie są identyczne i wygenerują ostrzeżenie w języku Microsoft C/C++.
#define multiply( f1, f2 ) ( f1 * f2 )
#define multiply( a1, a2 ) ( b1 * b2 )
END Microsoft Specific
W tym przykładzie przedstawiono dyrektywę #define :
#define WIDTH 80
#define LENGTH ( WIDTH + 10 )
Pierwsza instrukcja definiuje identyfikator WIDTH
jako stałą całkowitą 80 i definiuje LENGTH
jako WIDTH
i stałą całkowitą 10. Każde wystąpienie elementu LENGTH
jest zastępowane przez (WIDTH + 10
). Z kolei każde wystąpienie WIDTH + 10
elementu jest zastępowane wyrażeniem (80 + 10
). Nawiasy wokół WIDTH + 10
są ważne, ponieważ kontrolują interpretację w instrukcjach, takich jak następujące:
var = LENGTH * 20;
Po etapie przetwarzania wstępnego instrukcja stanie się:
var = ( 80 + 10 ) * 20;
który daje wartość 1800. Bez nawiasów wynik to:
var = 80 + 10 * 20;
który daje wartość 280.
Specyficzne dla firmy Microsoft
Definiowanie makr i stałych za pomocą opcji /D kompilatora ma taki sam efekt jak użycie dyrektywy #define przetwarzania wstępnego na początku pliku. Za pomocą opcji /D można zdefiniować maksymalnie 30 makr.
END Microsoft Specific