Preprocesory C

Preprocesory C

Preprocesory to programy, które przetwarzają kod źródłowy przed rozpoczęciem właściwej kompilacji. Nie są one częścią procesu kompilacji, ale działają oddzielnie, umożliwiając programistom modyfikację kodu przed kompilacją.

  • Jest to pierwszy krok, przez który przechodzi kod źródłowy C podczas konwersji do pliku wykonywalnego.
  • Główne typy dyrektyw preprocesora to  Makra Kompilacja warunkowa dołączania plików i inne dyrektywy, takie jak #undef #pragma itp.
  • Głównie te dyrektywy służą do zastąpienia danej sekcji kodu C innym kodem C. Na przykład, jeśli napiszemy „#define PI 3.14”, wówczas preprocesor zastąpi PI numerem 3.14.
Preprocesory C

Rodzaje preprocesorów C

Wszystkie powyższe preprocesory można podzielić na 4 typy:

Makra

Makra służą do definiowania stałych lub tworzenia funkcji, które są zastępowane przez preprocesor przed skompilowaniem kodu. Dwa preprocesory #określić I #undef służą do tworzenia i usuwania makr w języku C.

#określić wartość tokenu
#undef znak

gdzie po wstępnej obróbce znak zostanie rozszerzony do swojego wartość w programie.

Przykład:

C
   #include         // Macro Definition   #define LIMIT 5   int     main  (){      for     (  int     i     =     0  ;     i      <     LIMIT  ;     i  ++  )     {      printf  (  '%d   n  '       i  );      }      return     0  ;   }   

Wyjście
0 1 2 3 4  

W powyższym programie przed rozpoczęciem kompilacji słowo LIMIT zostaje zastąpione przez 5. Słowo 'LIMIT' w definicji makro nazywa się szablonem makra I „5” to ekspansja makro.

Notatka Na końcu definicji makra nie ma średnika (;). Definicje makr nie wymagają średnika na końcu.

Są też tacy Predefiniowane makra w C które są przydatne w zapewnianiu różnych funkcjonalności naszego programu.

Makro zdefiniowane wcześniej można niezdefiniować przy użyciu preprocesora #undef. Na przykład w powyższym kodzie

C
   #include         // Macro Definition   #define LIMIT 5   // Undefine macro   #undef LIMIT   int     main  (){      for     (  int     i     =     0  ;     i      <     LIMIT  ;     i  ++  )     {      printf  (  '%d   n  '       i  );      }      return     0  ;   }   


Wyjście:

 ./Solution.c: In function 'main': ./Solution.c:13:28: error: 'MAX' undeclared (first use in this function) printf('MAX is: %dn' MAX); ^ ./Solution.c:13:28: note: each undeclared identifier is reported only once for each function it appears in  

Makra z argumentami

Możemy także przekazywać argumenty do makr. Makra te działają podobnie do funkcji. Na przykład

# określić foo(a b) a + b
#zdefiniuj funkcję(r) r * r

Rozumiemy to za pomocą programu:

C
   #include         // macro with parameter   #define AREA(l b) (l * b)   int     main  (){      int     a     =     10       b     =     5  ;          // Finding area using above macro      printf  (  '%d'       AREA  (  a       b  ));      return     0  ;   }   

Wyjście
Area of rectangle is: 50  

Wyjaśnienie: W powyższym programie makro POWIERZCHNIA(lb) definiuje się do obliczania pola prostokąta poprzez pomnożenie jego długość (l) I szerokość (b) . Gdy POWIERZCHNIA(ab) nazywa się to rozszerza się do (a * b) a wynik jest obliczany i drukowany.

Proszę zapoznać się Rodzaje makr w C aby uzyskać więcej przykładów i typów.

Dołączenie pliku

Dołączanie plików umożliwia dołączenie plików zewnętrznych (biblioteki plików nagłówkowych itp.) do bieżącego programu. Zwykle odbywa się to za pomocą #włączać dyrektywa, która może zawierać zarówno pliki systemowe, jak i pliki zdefiniowane przez użytkownika.

Składnia

Istnieją dwa sposoby dołączania plików nagłówkowych.

#włączać
#włączać „nazwa pliku”

The ' <' I nawiasy „>”. powiedz kompilatorowi, aby szukał pliku w standardowy katalog chwila podwójne cudzysłowy ( ' ' ) powiedz kompilatorowi, aby wyszukał plik nagłówkowy w katalogu pliku źródłowego.

Przykład:

C
   // Includes the standard I/O library   #include            int     main  ()     {      printf  (  'Hello World'  );          return     0  ;   }   

Wyjście
Hello World 

Kompilacja warunkowa

Kompilacja warunkowa pozwala na włączenie lub wykluczenie części kodu w zależności od określonych warunków. Jest to przydatne do tworzenia kodu specyficznego dla platformy lub do debugowania. Istnieją następujące dyrektywy preprocesora warunkowego: #if #ifdef #ifndef else #elif i #endif

Składnia

Ogólna składnia preprocesorów warunkowych jest następująca:

#Jeśli
// jakiś kod
#elif
// trochę więcej kodu
#w przeciwnym razie
// Jeszcze trochę kodu
#endif

Dyrektywa #endif służy do zamykania dyrektyw otwierających #if #ifdef i #ifndef.

Przykład

C
   #include         // Defining a macro for PI   #define PI 3.14159   int     main  (){       // Check if PI is defined using #ifdef   #ifdef PI      printf  (  'PI is defined  n  '  );   // If PI is not defined check if SQUARE is defined   #elif defined(SQUARE)      printf  (  'Square is defined  n  '  );   // If neither PI nor SQUARE is defined trigger an error   #else      #error 'Neither PI nor SQUARE is defined'   #endif   // Check if SQUARE is not defined using #ifndef   #ifndef SQUARE      printf  (  'Square is not defined'  );   // If SQUARE is defined print that it is defined   #else      printf  (  'Square is defined'  );   #endif      return     0  ;   }   

Wyjście
PI is defined Square is not defined 

Wyjaśnienie: W kodzie tym zastosowano dyrektywy warunkowe preprocesora ( #ifdef #elif i #ifndef ), aby sprawdzić, czy określone makra ( LICZBA PI I KWADRAT ) są zdefiniowane. Ponieważ zdefiniowano PI, program wypisuje „ PI jest zdefiniowane 'następnie sprawdza, czy SQUARE nie jest zdefiniowany i wypisuje ' Kwadrat nie jest zdefiniowany '.

Inne dyrektywy

Oprócz podstawowych dyrektyw preprocesora C udostępnia także inne dyrektywy służące do zarządzania zachowaniem kompilatora i debugowaniem.

#pragma:

Dostarcza kompilatorowi szczegółowe instrukcje umożliwiające kontrolowanie jego zachowania. Służy do wyłączania ostrzeżeń, ustawiania wyrównania itp.

Składnia

#pragma dyrektywa

Niektóre z dyrektyw #pragma omówiono poniżej: 

  1. #pragma uruchomienie: Dyrektywy te pomagają nam określić funkcje, które są potrzebne do uruchomienia przed uruchomieniem programu (zanim kontrola przejdzie do main()).
  2. #pragma wyjście : Te dyrektywy pomagają nam określić funkcje, które są potrzebne do uruchomienia tuż przed wyjściem programu (tuż przed powrotem sterowania z funkcji main()).

Przykład

C
   #include         void     func1  ();   void     func2  ();   // specifying funct1 to execute at start   #pragma startup func1   // specifying funct2 to execute before end   #pragma exit func2   void     func1  ()     {     printf  (  'Inside func1()  n  '  );     }   void     func2  ()     {     printf  (  'Inside func2()  n  '  );     }   int     main  (){      void     func1  ();      void     func2  ();      printf  (  'Inside main()  n  '  );      return     0  ;   }   

Wyjście
Inside main()  

Powyższy kod wygeneruje dane wyjściowe podane powyżej, gdy zostanie uruchomiony na kompilatorach GCC, podczas gdy oczekiwany wynik będzie następujący:

Oczekiwany wynik

 Inside func1() Inside main() Inside func2()   

Dzieje się tak, ponieważ GCC nie obsługuje uruchamiania lub zamykania #pragma. Możesz jednak użyć poniższego kodu dla oczekiwanych wyników w kompilatorach GCC. 

C
   #include         void     func1  ();   void     func2  ();   void     __attribute__  ((  constructor  ))     func1  ();   void     __attribute__  ((  destructor  ))     func2  ();   void     func1  ()   {      printf  (  'Inside func1()  n  '  );   }   void     func2  ()   {      printf  (  'Inside func2()  n  '  );   }   int     main  ()   {      printf  (  'Inside main()  n  '  );      return     0  ;   }   

Wyjście
Inside func1() Inside main() Inside func2()  

W powyższym programie użyliśmy niektórych specyficzne składnie tak, że jedna z funkcji jest wykonywana przed funkcją główną, a druga po funkcji głównej.

Utwórz quiz