Preprocesory celu-C

Plik Objective-C Preprocessornie jest częścią kompilatora, ale stanowi oddzielny krok w procesie kompilacji. Mówiąc prościej, preprocesor Objective-C jest tylko narzędziem do zastępowania tekstu i instruuje kompilator, aby wykonał wymagane przetwarzanie wstępne przed właściwą kompilacją. Będziemy nazywać Preprocesor Objective-C jako OCPP.

Wszystkie polecenia preprocesora zaczynają się od symbolu krzyżyka (#). Musi to być pierwszy niepusty znak, a dla czytelności dyrektywa preprocesora powinna zaczynać się w pierwszej kolumnie. Poniższa sekcja zawiera listę wszystkich ważnych dyrektyw preprocesora -

Sr.No. Dyrektywa i opis
1

#define

Zastępuje makro preprocesora

2

#include

Wstawia określony nagłówek z innego pliku

3

#undef

Nie definiuje makra preprocesora

4

#ifdef

Zwraca wartość true, jeśli to makro jest zdefiniowane

5

#ifndef

Zwraca wartość true, jeśli to makro nie jest zdefiniowane

6

#if

Testuje, czy warunek czasu kompilacji jest prawdziwy

7

#else

Alternatywa dla #if

8

#elif

#else an #if w jednej instrukcji

9

#endif

Warunkowe zakończenie preprocesora

10

#error

Wyświetla komunikat o błędzie na stderr

11

#pragma

Wydaje specjalne polecenia kompilatorowi przy użyciu standardowej metody

Przykłady preprocesorów

Przeanalizuj poniższe przykłady, aby zrozumieć różne dyrektywy.

#define MAX_ARRAY_LENGTH 20

Ta dyrektywa nakazuje OCPP zamianę wystąpień MAX_ARRAY_LENGTH na 20. Użyj #define dla stałych, aby zwiększyć czytelność.

#import <Foundation/Foundation.h>
#include "myheader.h"

Te dyrektywy mówią OCPP, aby pobrać plik Foundation.h z Foundation Frameworki dodaj tekst do bieżącego pliku źródłowego. Następna linia mówi OCPP, aby uzyskaćmyheader.h z katalogu lokalnego i dodaj zawartość do bieżącego pliku źródłowego.

#undef  FILE_SIZE
#define FILE_SIZE 42

To mówi OCPP, aby cofnął definicję istniejącego FILE_SIZE i zdefiniował go jako 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

To mówi OCPP, aby zdefiniował MESSAGE tylko wtedy, gdy MESSAGE nie jest jeszcze zdefiniowane.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Informuje to OCPP, aby wykonał proces dołączonych instrukcji, jeśli zdefiniowano DEBUG. Jest to przydatne, jeśli przekazujesz flagę -DDEBUG do kompilatora gcc w czasie kompilacji. Spowoduje to zdefiniowanie funkcji DEBUG, dzięki czemu można włączać i wyłączać debugowanie w locie podczas kompilacji.

Predefiniowane makra

ANSI C definiuje szereg makr. Chociaż każdy z nich jest dostępny do użytku w programowaniu, predefiniowanych makr nie należy bezpośrednio modyfikować.

Sr.No. Makro i opis
1

__DATE__

Bieżąca data jako literał znakowy w formacie „MMM DD RRRR”

2

__TIME__

Bieżący czas jako literał znaku w formacie „HH: MM: SS”

3

__FILE__

Zawiera bieżącą nazwę pliku jako literał ciągu.

4

__LINE__

Zawiera bieżący numer wiersza jako stałą dziesiętną.

5

__STDC__

Zdefiniowany jako 1, gdy kompilator jest zgodny ze standardem ANSI.

Wypróbujmy następujący przykład -

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"File :%s\n", __FILE__ );
   NSLog(@"Date :%s\n", __DATE__ );
   NSLog(@"Time :%s\n", __TIME__ );
   NSLog(@"Line :%d\n", __LINE__ );
   NSLog(@"ANSI :%d\n", __STDC__ );
   
   return 0;
}

Gdy powyższy kod w pliku main.m jest kompilowany i wykonywany, daje następujący wynik -

2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1

Operatory preprocesora

Preprocesor Objective-C oferuje następujące operatory, które pomogą Ci w tworzeniu makr -

Kontynuacja makra (\)

Makro zwykle musi znajdować się w jednym wierszu. Operator kontynuacji makra służy do kontynuowania makra, które jest zbyt długie dla pojedynczego wiersza. Na przykład -

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

Stringize (#)

Operator stringize lub number-sign („#”) używany w definicji makra konwertuje parametr makra na stałą łańcuchową. Ten operator może być używany tylko w makrze, które ma określony argument lub listę parametrów. Na przykład -

#import <Foundation/Foundation.h>

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!

Wklejanie tokena (##)

Operator wklejania tokenu (##) w definicji makra łączy dwa argumenty. Umożliwia połączenie dwóch oddzielnych tokenów w definicji makra w jeden token. Na przykład -

#import <Foundation/Foundation.h>

#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

2013-09-14 05:48:14.859 demo[20683] token34 = 40

Jak to się stało, ponieważ ten przykład skutkuje następującym faktycznym wyjściem z preprocesora -

NSLog (@"token34 = %d", token34);

Ten przykład pokazuje konkatenację tokenu ## n w token34 i tutaj użyliśmy obu stringize i token-pasting.

Operator zdefiniowany ()

Preprocesor definedoperator jest używany w wyrażeniach stałych do określenia, czy identyfikator jest zdefiniowany za pomocą #define. Jeśli określony identyfikator jest zdefiniowany, wartością jest prawda (różna od zera). Jeśli symbol nie jest zdefiniowany, wartość jest fałszywa (zero). Zdefiniowany operator jest określony w następujący sposób -

#import <Foundation/Foundation.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   NSLog(@"Here is the message: %s\n", MESSAGE);  
   return 0;
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!

Sparametryzowane makra

Jedną z potężnych funkcji OCPP jest możliwość symulacji funkcji przy użyciu sparametryzowanych makr. Na przykład możemy mieć kod do kwadratu liczby w następujący sposób -

int square(int x) {
   return x * x;
}

Możemy przepisać powyższy kod za pomocą makra w następujący sposób -

#define square(x) ((x) * (x))

Makra z argumentami należy definiować przy użyciu rozszerzenia #definedyrektywy, zanim będzie można ich użyć. Lista argumentów jest ujęta w nawiasy i musi następować bezpośrednio po nazwie makra. Spacje są niedozwolone między nazwą makra a otwartym nawiasem. Na przykład -

#import <Foundation/Foundation.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20