Som navnet antyder, er præprocessorer programmer, der behandler vores kildekode før kompilering. Der er en række trin involveret mellem at skrive et program og udføre et program i C / C++. Lad os tage et kig på disse trin, før vi rent faktisk begynder at lære om præprocessorer.
Du kan se de mellemliggende trin i ovenstående diagram. Den kildekode, som programmører har skrevet, gemmes i filen program.c. Denne fil behandles derefter af præprocessorer, og der genereres en udvidet kildekodefil med navnet program. Denne udvidede fil kompileres af compileren, og der genereres en objektkodefil med navnet program .obj. Endelig forbinder linkeren denne objektkodefil med objektkoden for biblioteksfunktionerne for at generere den eksekverbare fil program.exe.
Preprocessorprogrammer indeholder præprocessordirektiver, der fortæller compileren, at den skal forbehandle kildekoden, inden den kompileres. Alle disse præprocessordirektiver begynder med et “#”-symbol (hash). ‘#’-symbolet angiver, at den erklæring, der begynder med #, skal sendes til præprocessorprogrammet, og præprocessorprogrammet vil udføre denne erklæring. Eksempler på nogle præprocessordirektiver er: #include, #define, #ifndef osv. Husk, at symbolet # kun angiver en vej til præprocessoren, og at kommandoer som f.eks. include behandles af præprocessorprogrammet. For eksempel vil include inkludere ekstra kode til dit program. Vi kan placere disse præprocessordirektiver hvor som helst i vores program.
Der er 4 hovedtyper af præprocessordirektiver:
- Makroer
- Filinklusion
- Konditionel kompilering
- Andre direktiver
Lad os nu lære om hvert af disse direktiver i detaljer.
- Makroer: Makroer er et stykke kode i et program, som får et eller andet navn. Når compileren støder på dette navn, erstatter compileren navnet med det faktiske kodestykke. ‘#define’-direktivet bruges til at definere en makro. Lad os nu forstå makrodefinitionen ved hjælp af et program:
#include <iostream>
#define LIMIT 5
int
main()
{
for
(
int
i = 0; i < LIMIT; i++) {
std::cout << i <<
"\n"
;
}
return
0;
}
#include <stdio.h>
#define LIMIT 5
int
main()
{
for
(
int
i = 0; i < LIMIT; i++) {
printf
(
"%d \n"
,i);
}
return
0;
}
Output:
01234
I ovenstående program erstatter compileren ordet LIMIT med 5, når den udfører ordet LIMIT. Ordet “LIMIT” i makrodefinitionen kaldes en makroskabelon, og “5” er en makroudvidelse.
Bemærk: Der er ikke noget semikolon(‘;’) i slutningen af makrodefinitionen. Makrodefinitioner behøver ikke et semikolon til at slutte.
Makroer med argumenter: Vi kan også overdrage argumenter til makroer. Makroer defineret med argumenter fungerer på samme måde som funktioner. Lad os forstå dette med et program:
#include <iostream>
#define AREA(l, b) (l * b)
int
main()
{
int
l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
std::cout <<
"Area of rectangle is: "
<< area;
return
0;
}
#include <stdio.h>
#define AREA(l, b) (l * b)
int
main()
{
int
l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
printf
(
"Area of rectangle is: %d"
, area);
return
0;
}
Output:
Area of rectangle is: 50
Vi kan se af ovenstående program, at når compileren finder AREA(l, b) i programmet, erstatter den det med udsagnet (l*b) . Ikke nok med dette, de værdier, der er overgivet til makroskabelonen AREA(l, b), vil også blive erstattet i erklæringen (l*b). Derfor vil AREA(10, 5) være lig med 10*5.
- Inddragelse af fil: Denne type præprocessordirektiv fortæller compileren, at den skal inkludere en fil i kildekodeprogrammet. Der er to typer filer, som kan inkluderes af brugeren i programmet:
- Headerfil eller standardfiler: Disse filer indeholder definition af foruddefinerede funktioner som printf(), scanf() osv. Disse filer skal medtages for at kunne arbejde med disse funktioner. Forskellige funktioner er deklareret i forskellige header-filer. F.eks. findes standard I/O-funktioner i “iostream”-filen, mens funktioner, der udfører strengoperationer, findes i “string”-filen.
Syntaks:
- Headerfil eller standardfiler: Disse filer indeholder definition af foruddefinerede funktioner som printf(), scanf() osv. Disse filer skal medtages for at kunne arbejde med disse funktioner. Forskellige funktioner er deklareret i forskellige header-filer. F.eks. findes standard I/O-funktioner i “iostream”-filen, mens funktioner, der udfører strengoperationer, findes i “string”-filen.
#include< file_name >
hvor file_name er navnet på den fil, der skal inkluderes. Parenteserne ‘<‘ og ‘>’ fortæller compileren, at den skal lede efter filen i standardmappen.
- brugerdefinerede filer: Når et program bliver meget stort, er det god praksis at opdele det i mindre filer og inkludere dem, når det er nødvendigt. Disse typer af filer er brugerdefinerede filer. Disse filer kan inkluderes som:
#include"filename"
- betinget kompilering: Direktiver til betinget kompilering er en type direktiver, som hjælper med at kompilere en bestemt del af programmet eller springe kompilering af en bestemt del af programmet over på grundlag af visse betingelser. Dette kan gøres ved hjælp af de to præprocesseringskommandoer “ifdef” og “endif”.
Syntaks:
#ifdef macro_name statement1; statement2; statement3; . . . statementN;#endif
Hvis makroen med navnet ‘macroname’ er defineret, vil blokken af instruktioner blive udført normalt, men hvis den ikke er defineret, vil compileren simpelthen springe denne blok af instruktioner over.
- Andre direktiver: Ud over de ovennævnte direktiver er der to andre direktiver, som ikke er almindeligt anvendte. Disse er:
- #undef-direktivet: #undef-direktivet bruges til at dedefinere en eksisterende makro. Dette direktiv fungerer som:
#undef LIMIT
Ved anvendelse af denne anvisning vil den eksisterende makro LIMIT blive dedefineret. Efter denne erklæring vil enhver “#ifdef LIMIT”-erklæring blive evalueret til falsk.
- #pragma Direktiv: Dette direktiv er et direktiv til et særligt formål og bruges til at slå nogle funktioner til eller fra. Denne type direktiver er compilerspecifikke, dvs. at de varierer fra compiler til compiler. Nogle af #pragma-direktiverne gennemgås nedenfor:
- #pragma startup og #pragma exit: Disse direktiver hjælper os med at angive de funktioner, der skal køres før programmets opstart( før kontrollen overgår til main()) og lige før programmets afslutning (lige før kontrollen vender tilbage fra main()).
Bemærk: Nedenstående program vil ikke fungere med GCC-compilere.
Kig på nedenstående program:
- #pragma startup og #pragma exit: Disse direktiver hjælper os med at angive de funktioner, der skal køres før programmets opstart( før kontrollen overgår til main()) og lige før programmets afslutning (lige før kontrollen vender tilbage fra main()).
#include <bits/stdc++.h>
using
namespace
std;
void
func1();
void
func2();
#pragma startup func1
#pragma exit func2
void
func1()
{
cout <<
"Inside func1()\n"
;
}
void
func2()
{
cout <<
"Inside func2()\n"
;
}
int
main()
{
void
func1();
void
func2();
cout <<
"Inside main()\n"
;
return
0;
}
#include <stdio.h>
void
func1();
void
func2();
#pragma startup func1
#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;
}
Output:
Inside func1()Inside main()Inside func2()
Overstående kode vil give nedenstående output, når den køres på GCC-kompilere:
Inside main()
Dette sker, fordi GCC ikke understøtter #pragma startup eller exit. Du kan dog bruge nedenstående kode for at få et lignende output på GCC-kompilatorer.
#include <stdio.h>
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;
}
- #pragma warn Direktiv: Dette direktiv bruges til at skjule de advarselsmeddelelser, der vises under kompilering.
Vi kan skjule advarslerne som vist nedenfor:- #pragma warn -rvl:
- #pragma warn -rvl: Dette direktiv skjuler de advarsler, der kommer frem, når en funktion, som skal returnere en værdi, ikke returnerer en værdi.
- #pragma warn -par:
- #pragma warn -par: Dette direktiv skjuler de advarsler, der opstår, når en funktion ikke bruger de parametre, der er overgivet til den.
- #pragma warn -rch: Dette direktiv skjuler de advarsler, der vises, når en kode er utilgængelig. For eksempel: Enhver kode, der er skrevet efter return-erklæringen i en funktion, er uopnåelig.
Denne artikel er bidraget af Harsh Agarwal. Hvis du kan lide GeeksforGeeks og gerne vil bidrage, kan du også skrive en artikel ved hjælp af contribute.geeksforgeeks.org eller sende din artikel på mail til [email protected]. Se din artikel blive vist på GeeksforGeeks’ hovedside, og hjælp andre nørder.