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.
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 inMakra 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 * rRozumiemy 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ścieArea of rectangle is: 50Wyjaś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 #includeint main () { printf ( 'Hello World' ); return 0 ; }
WyjścieHello WorldKompilacja 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
#endifDyrektywa #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ściePI is defined Square is not definedWyjaś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:
- #pragma uruchomienie: Dyrektywy te pomagają nam określić funkcje, które są potrzebne do uruchomienia przed uruchomieniem programu (zanim kontrola przejdzie do main()).
- #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#includevoid 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ścieInside 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#includevoid 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ścieInside 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