Vad ingår i c. Direktiven om förprocessorer

Ett av de vanligaste misstagen programmerare gör är att göra cyklar, hjul etc. Det är otroligt svårt att vara oense med detta, för i praktiken är det, men hur man hanterar det? Många programmerare kommer att berätta med en röst: lär dig STL - ett standardbibliotek som innehåller utvecklingen av många utvecklare av ett programmeringsspråk, och kan också vara till stor hjälp för utveckling nytt program... I den här artikeln kommer vi att titta närmare på vad C # Include är, hur det fungerar och vad det skapades för. Artikeln rekommenderas inte bara för nybörjare operativ system Windows, men också för första och andra årsprogrammerare.

Vad det är?

Till att börja med är det värt att upplysa dem som står inför programmering för första gången och som dessutom inte vet om komplexiteten i byggprogram. Ursprungligen programmerade människor in maskinspråk, efter vetenskapliga och tekniska framsteg inom mikroprocessorer, beslutades att skapa ett operativsystem för stora användare.

Idén var bra, men väldigt svår att genomföra, eftersom det skulle ha tagit årtionden om de användes för att bygga program. Samtidigt anförtrotts en annan uppgift: att skapa ett programmeringsspråk där det skulle vara enkelt att skapa ett operativsystem, ett sådant språk var C.

Ja, många kommer att säga att det inte finns där som i C ++. Detta är sant, men det är möjligt att skriva ett operativsystem om funktioner, vilket framgår av Linux och Windows-kärna... I detta programmeringsspråk ingår varje bibliotek i början av filen, allt tack vare #include C-förprocessormärkningen. Efter nyckelord med hash ska vara namnet på filen enligt följande:<так, если файл в папке с компилятором>och “så om det ligger utanför kompilatormappen”. Exempel korrekt anslutning: # inkludera

Under bearbetningen går kompilatorn igenom varje sådan etikett, tillägger nödvändiga filer och skickar sedan det hela till länken och tolk som ingår i kompilatorns uppsättning. Många C-funktioner fungerar ganska bra i C ++, men inte i omvänd ordning- du borde definitivt veta.

Visual C Inkludera bibliotek

Så. Vi har redan räknat ut vad Include är, nu kan vi arbeta med det, men du vet fortfarande inget om IDE - en integrerad utvecklingsmiljö. IDE är i grunden ett smart anteckningsblock, om det är för förkortat. Du skriver din kod och sedan vill du kompilera den. Om du arbetade i Linux måste du kompilera genom kommandoraden, inklusive manuellt eller genom en makefil, alla icke-standardbibliotek, men i IDE görs allt detta automatiskt.

Också på gång full kontrollöver applikationen så att den inte av misstag bryter systemet. Du kan titta på resurserna som konsumeras, och viktigast av allt förklaras fel så mycket detaljerat som möjligt och med indikationen på raden.

En av bästa IDE med rätta överväga Microsoft Visual Studio. Dessutom har själva språket i denna utvecklingsmiljö ändrats något, så i denna punkt vi analyserar de mest populära Visual C-standardbiblioteken.

Lista över bibliotek:

  1. Time.h - rubrikfil för att arbeta med tidsintervall.
  2. Stdlib.h - rubrikfil med den inkluderade klassen i standardbiblioteket.
  3. Stdio.h är standardinmatnings- / utgångsbiblioteket.
  4. Fsteam.h - ett bibliotek för att arbeta med filer.

Det finns också andra, mycket mer specifika bibliotek, men deras studie rekommenderas endast när du bara behöver arbeta med funktionerna Visuell Studio... Förresten, det finns flera varianter av denna IDE, som uppsättningarna är beroende av. standardbibliotek, till exempel i PRO-version det finns verktyg för att arbeta med Android, men det vanliga gör det inte.

Lista över alla Inkludera med förklaringar i C

Vet du vad klasserna är? Om inte, har du frågor om varför biblioteken slutar med ".h". Kort sagt, lektioner är någon form av Lego-tegelstenar som du kan infoga i ditt program. För att göra det enkelt - de finns. Enligt regeln för god programmeringspraxis måste deklarationerna om deras parametrar fyllas i rubrikfilen och själva körningen i en separat med tillägget ”*. med "eller" *. cpp ".

Innan du börjar förklaringen måste du förstå C-biblioteket: Inkludera - det här biblioteket skapades speciellt för Windows-operativsystemet nödvändiga funktioner och klasser för att inte bara arbeta med systemets grafiska komponent utan även med parametrar, exakta inställningar, kommandorad och många andra. Om du vill skriva program för Windows bör det vara det första i studielistan.

STL-lista:

  1. Vector.h - arbetar med dynamiskt minne kallade vektorer.
  2. Map.h - speciella ordböcker.
  3. Iostream är ett bibliotek för att arbeta med in- och utdata till konsolen.
  4. Fout - arbetar med filer. Den analoga är C Include .
  5. Stdlib är en klass som ärvs från andra STL.
  6. Errno.h - rubrikfil för utskriftsfel till konsolen.
  7. Ctype.h - rubrikfil för att arbeta med ASCI-kod.

Standardbiblioteket är en otrolig samling av olika skapelser från skaparen av språket, liksom många andra programmerare. Använda STL uppmuntras på alla nivåer. Det finns också många andra mindre kända bibliotek, till exempel C Include är ett bibliotek för att arbeta med systemsignaler, men deras studier krävs i högt specialiserade program.

I C ++

Som redan nämnts: C ++ tog det bästa från C-språket. Det viktigaste är kompilatorn, även om det anses vara en av de långsammaste, eftersom det måste gå igenom varje fil, varje rad för att hitta speciella etiketter, sedan ge allt till länken, och medan allt kommer att anslutas, kommer mycket tid att gå, så stora projekt tar upp till en och en halv timme.

Plus är hög hastighet det resulterande programmet, dvs. dess prestanda, därför givet språk används nästan överallt, när det är möjligt, även i hushållsprodukter det finns en obligatorisk rad med C ++ - kod.

Vad händer om det inte finns någon STL på datorn?

Det finns dynamisk och statisk sammanställning i C och C ++. Beroende på vilket system produkten tillverkas för, är motsvarande bibliotek också inbäddade. Det finns till exempel inget Windows.h-bibliotek på Linux och i Windows finns det inget x11.lib (bibliotek har en sådan förlängning - * .lib). Detta faktum måste övervägas, men tack vare smarta IDE: er kan du välja mellan dynamisk och statisk byggnad... Med en dynamik - från systemet, specifika bibliotek och i en statisk, tar projektet mer, men kommer garanterat att gå till specifikt system.

Till sist

Vi hoppas att du gillade dig i en så fantastisk och färgstark programmeringsvärld. Om du aldrig har skrivit eget program, vi rekommenderar att du börjar göra det just nu, eftersom smaken på segern över bilen är för trevlig. Vi hoppas också att lärande med Include gick smidigt. Hur som helst kan du besöka MDSN och ta reda på mer.

#omfatta

#Inkludera direktiv infogar kod från den angivna filen till den aktuella filen, det vill säga helt enkelt genom att ansluta en annan fil, kan vi använda dess funktioner, klasser, variabler. Huvudfiler finns vanligtvis i den aktuella katalogen eller i standardsystemkatalogen.

Rubrikfiler ingår vid kompileringen eller som en fil som ingår i ditt projekt. Denna funktion beror på den specifika implementeringen av din kompilator, så för att få mer detaljerad information, gräva i dina kompilatorinställningar.

Om inkluderingsfilen inte hittas misslyckas kompileringsprocessen.

# Definiera direktivet

Direktivet #define har två former:

  • definition av konstanter;
  • definition av makron.
Definiera konstanter
#define nameToken value

När du använder namnet på konstanten - nameToken kommer den att ersättas med värdevärdet, det vill säga ungefär - detta är samma variabel vars värde inte kan ändras. Låt oss se ett exempel på att använda en konstant:

#omfatta #define TEXT "Mars" // definiera en konstant int main () (std :: cout<< TEXT; return 0; }

Som du kan se, för att komma åt värdet på en konstant använder vi helt enkelt dess namn.

Definiera parametrerade makron

#define nameMacros (arg1, arg2, ...) expression

Låt oss till exempel definiera ett makro som returnerar högst två värden.

#definiera MAX (num1, num2) ((num1)> (num2)? (num1): (num2))

För att definiera ett makro med flera rader måste en symbol placeras i slutet av varje rad, som informerar förprocessorn om att makrot ännu inte har slutförts.

#Undef-direktivet

#Undef-direktivet åsidosätter ett konstant eller förprocessormakro som tidigare definierats med #define-direktivet.

#undef nameToken

Låt oss se ett exempel på att använda #undef-direktivet:

#define E 2.71828 // tidigare definierat makro int sumE = E + E; // call to macro #undef E // nu är E inte ett makro

Normalt används #undef-direktivet för att avmarkera en tidigare definierad konstant eller makro i ett litet område av programmet. Detta görs så att för hela programmet förblir ett makro eller en konstant, och för ett visst område kan samma makro eller en konstant omdefinieras. Det skulle vara osäkert att åsidosätta en konstant genom hela programmet, men i en kort omfattning är det relativt säkert. #Undef-direktivet är det enda sättet skapande av detta omfång, eftersom omfattningen av makron eller konstanter är från direktivet #define till #undef.

#Om direktivet

#if värde // kod som kommer att köras om värdet är sant #elsif värde1 // denna kod kommer att köras om värde1 är sant #else // kod som kommer att köras i annat#endif

Direktivet #if kontrollerar om värde värde true och i så fall exekveras koden före det avslutande #endif-direktivet. Annars kommer koden i #if inte att kompileras, den tas bort av kompilatorn, men detta påverkar inte källa i källan.

Observera att #if kan innehålla kapslade #elsif- och #else-direktiv. Nedan följer en exempelkod för kommentering av kodblock med hjälp av efter konstruktion:

#if 0 // kod för att kommentera #endif

Om du har kodblock i ditt program som innehåller flera radkommentarer och du måste slå in hela kodblocket i en kommentar, fungerar inget om du använder / * multi-line comment * /. En annan sak är konstruktionen av #if #endif-direktiv.

#Ifdef-direktivet

#ifdef nameToken // kod som kommer att köras om nameToken är definierad #else // kod som kommer att köras om nameToken inte är definierad #endif

#Ifdef-direktivet kontrollerar om en makro- eller symbolkonstant tidigare har definierats som #define. Om - ja, innehåller kompilatorn koden som ligger mellan direktiven #ifdef och #else i programmet, om nameToken inte definierades tidigare, körs koden mellan #else och #endif, eller, om det inte finns någon #else direktiv hoppar kompilatorn omedelbart till # endif. Till exempel definieras __cpp-makrot i C ++, men inte i C. Du kan använda detta faktum för att blanda C- och C ++ -kod med #ifdef-direktivet:

#ifdef __cpp // C ++ - kod #else // C-kod #endif

#Indef-direktivet

#ifndef nameToken // kod som kommer att köras om nameToken inte är definierad #else // code som kommer att köras om nameToken är definierad #endif

#Ifndef-direktivet kontrollerar om en makro- eller symbolkonstant tidigare har definierats som #define. Om ja, innehåller kompilatorn koden som ligger mellan #else- och #endif-direktiven i programmet, om nameToken inte tidigare definierades, körs koden mellan #ifndef och #else, eller om det inte finns något #else-direktiv hoppar kompilatorn omedelbart till # endif. #Ifndef-direktivet kan användas för att inkludera rubrikfiler. om de inte är anslutna, använd för detta en symbolisk konstant som en indikator på funktionaliteten kopplad till projektet.

Till exempel finns det i rubrikfilen ett klassgränssnitt som måste anslutas till projektet om den här klassen inte tidigare var ansluten.

#ifndef PRODUCT_H #define PRODUCT_H class Product (// klasskod ...); #endif PRODUCT_H

I detta fall används den tomma symboliska konstanten PRODUCT_H, som endast kan definieras i programmet tillsammans med produktklassen. Därför, om vi finner att konstanten PRODUCT_H redan är definierad, så är klassen också och då kommer vi att utesluta omdefiniering klass, vilket kan resultera i ett åsidosättningsfel.

#Feldirektivet

#error "Den här koden ska inte kompileras"

Direktivet #error låter dig visa ett meddelande i kompileringsfellistan om ett fel inträffar. Detta direktiv är mest användbart i kombination med #if, #elsif, #else-direktiv för att kontrollera sammanställning om något villkor inte är sant. Till exempel:

#ifndef __unix__ // __unix__ stöds vanligtvis på Unix-system #error "Stöds endast på Unix" #endif

__FILE__ förprocessormakro

Makrot __FILE__ förprocessor expanderar till fullständig sökväg till aktuell fil (källa). __FILE__ är användbart när du skapar en loggfil, genererar felmeddelanden avsedda för programmerare, vid felsökning av kod.

Int-fel (const char * adrFile, const std :: string & erMessage) (cerr<< "[" << adrFile << "]" << arMessage << endl; } #define LOG(erMessage) error(__FILE__, arMessage) // макрос LOG может быть использован для получения сообщений об ошибках, которые выводятся на стандартный поток ошибок

Makrot __FILE__ används ofta i kombination med makrot __LINE__, som ger det aktuella radnumret.

__LINE__ förprocessormakro

Makrot __LINE__ expanderar till det aktuella radnumret i källfilen som ett heltal. __LINE__ är användbart för att generera en loggfil eller generera radnummer felmeddelanden för programmerare vid felsökning av kod.

Int-fel (int nLine, const std :: string & erMessage) (cerr<< "[" << nLine << "]" << erMessage << endl; } #define LOG(erMessage) error(__LINE__, erMessage) // макрос LOG может быть использован для получения сообщений об ошибках, с указанием номеров строк, которые выводятся на стандартный поток ошибок

Makrot __LINE__ används ofta tillsammans med makrot __FILE__, som visar adressen till den aktuella källfilen.

__DATE__ förprocessormakro

Makrot __DATE__ expanderar till det aktuella datumet (kompileringstid) som [mmm dd åååå] (till exempel "7 december 2012") som en sträng. __DATE__ kan användas för att tillhandahålla information om sammanställningstid.

Cout<< __DATE__ << endl;

Du kan också använda makrot __TIME__ för att få aktuell kompileringstid.

__TIME__ förprocessormakro

Makrot __TIME__ expanderar vid aktuell tid (kompileringstid) i formatet hh: mm: cc i 24-timmarsformat (till exempel "22:29:12"). Makrot __TIME__ kan användas för att ge information om tiden vid en viss punkt i sammanställningen.

Cout<< __TIME__ << endl;

__TIMESTAMP__ förprocessormakro

Makrot __TIMESTAMP__ expanderar vid aktuell tid (kompileringstid) i formatet Ddd Mmm Datum hh :: mm :: ss åååå, tiden i 24-timmarsformat:

  • Ddd är den förkortade veckodagen,
  • mmm detta förkortas till en månad,
  • Datum - den aktuella dagen i månaden (1-31),
  • åååå är årets fyra siffror.

Till exempel "fre dec 7 00:42:53 2012". Makrot __TIMESTAMP__ kan användas för att få sammanställningsdatum och tidsinformation.

Cout<< __TIMESTAMP__ << endl;

Du kan också använda makrot __TIME__ för att få aktuell kompileringstid och makrot __DATE__ för att få datumet.

#Pragmatirektivet

#pragma kompilatorspecifikt tillägg

#Pragma-direktivet används för att komma åt specifika kompileringstillägg. Med hjälp av #pragma-direktivet med token en gång ber kompilatorn att inkludera rubrikfilen bara en gång, oavsett hur många gånger den importeras:

#pragma en gång // rubrikfil

I det här exemplet tillåter inte direktivet #pragma en gång att filen ingår i projektet flera gånger, det vill säga det förhindrar åsidosättande.

#Pragma-direktivet kan också användas för andra ändamål, till exempel används #pragma vanligtvis för att inaktivera varningar. Till exempel i MVS:

#pragma varning (inaktivera: 4018)

#Pragma-direktivet i det här exemplet används för att inaktivera 4018-varningar. Mer information om #pragma-direktivet finns i dokumentationen till din kompilator.

Makrooperatör #

#

Operatör # en texttoken i en citerad sträng. Låt oss se ett exempel:

#omfatta använder namnrymd std; #define message (s) cout<< "Сообщение: " #s << endl; int main() { message("GunGame"); return 0; }

Sammankoppla strängar och expandera meddelandemakrot till cout<< "Сообщение: GunGamen"; . Обратите внимание на то, что операция # должна использоваться совместно с аргументами, так как # ссылается на аргумент.

Makrooperatör ##

Operatören ## tar två separata tokens och limmer ihop dem för att bilda ett makro. Resultatet kan vara ett variabelnamn, klassnamn eller någon annan identifierare. Till exempel:

#definiera typ ch ## ar typ a; // variabel a är datatyp char, eftersom ch och ar är limmade i char

Låt oss överväga ett annat exempel på att använda ## -operatören, där vi kombinerar två tokens:

#define TOKENCONCAT (x, y) x ## y

När ett program anropar detta makro kombineras de två tokens till ett. Operation ## måste ha två operander.

PS.: Alla seriösa program måste ha en egen databas, vanligtvis används följande DBMS för att hantera databasen: MySQL, MsSQL, PostgreeSQL, Oracle, etc. När du installerar SQL Server kommer forumet på cyberforum.ru att vara en ersättningsbar assistent för du. Ställ dina frågor på detta forum, du kommer definitivt att få hjälp med att lösa ditt problem.

En förprocessor är ett speciellt program som ingår i C-kompilatorn. Den är avsedd för förbehandling av programtexten. Förprocessorn låter dig inkludera filer i programtexten och ange makrodefinitioner.
Förprocessorn arbetar med hjälp av speciella direktiv (instruktioner). De är markerade med en hash #. I slutet av raderna som anger direktiv på C-språket kan semikolonet utelämnas.

Grundläggande förbehandlingsdirektiv

#include - infogar text från den angivna filen
#define - definierar en makrodefinition (makro) eller symbolisk konstant
#undef - ångra den tidigare definitionen
#if - utför villkorlig sammanställning om ett konstant uttryck är sant
#ifdef - utför villkorlig sammanställning när en symbolisk konstant definieras
#ifndef - utför villkorlig sammanställning när symbolisk konstant är odefinierad
#else - gren av villkorlig sammanställning om uttrycket är falskt
#elif - villkorlig sammanställningsgren bildad genom att slå ihop annat och if
#endif - slutet på den villkorliga sammanställningsgrenen
#line - preprocessor ändrar det aktuella radnumret och namnet på den kompilerade filen
#error - utfärdar ett diagnosmeddelande
#pragma är en åtgärd som beror på en specifik implementering av kompilatorn.

#Inkludera direktivet

#Include-direktivet låter dig inkludera den angivna filen i programtexten. Om filen är ett standardbibliotek och finns i kompileringsmappen, är den innesluten i vinkelparenteser<> .
Om filen finns i den aktuella projektkatalogen anges den med citattecken "". För en fil som finns i en annan katalog måste du ange hela sökvägen i citattecken.

#omfatta
# inkludera "func.c"

# Definiera direktivet

I #define-direktivet kan du ange konstanter och makrodefinitioner i programtexten.
Allmän anmälningsform

#define Id Replacement


Fält Identifierare och Ersättningåtskilda av ett eller flera mellanslag.
Direktivet #define ber kompilatören att ersätta strängen som anges av argumentet Ersättning, istället för varje argument Identifierare i källfilen. Identifieraren ersätts inte om den finns i en kommentar, i en rad eller som en del av en längre identifierare.

1
2
3
4
5
6
7
8

#omfatta
#definiera A 3
int main ()
{
printf ("% d +% d =% d", A, A, A + A); // 3 + 3 = 6
getchar ();
returnera 0;
}

Kompilatorn tilldelar en eller annan typ till den beroende på konstantens värde. Med hjälp av suffix kan du åsidosätta typen av en konstant:

  • U eller u representerar en osignerad heltalskonstant;
  • F (eller f) låter dig beskriva en verklig konstant av typen float;
  • L (eller l) låter dig allokera en heltalskonstant 8 byte (lång int);
  • L (eller l) låter dig beskriva en riktig konstant av typen long double

#define A 280U // osignerad int
#define B 280LU // osignerad lång int
#define C 280 // int (long int)
#define D 280L // lång int
#define K 28.0 // double
#define L 28.0F // float
#define M 28.0L // lång dubbel

Den andra formen av syntax definierar ett funktionsliknande makro med parametrar. Det här formuläret tillåter en valfri lista med parametrar som måste vara inom parentes. Efter att ha definierat ett makro, varje efterföljande förekomst

identifierare (arg1, ..., argn)


ersatt av versionen av argumentet ersättning där faktiska argument ersätts med formella argument.

C-exempel: Beräkning av sinus för en vinkel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#omfatta
#omfatta
#omfatta
#define PI 3.14159265
#define SIN (x) sin (PI * x / 180)
int main ()
{
int c;
system ("chcp 1251");
system ("cls");
printf ( "Ange vinkeln i grader:");
scanf ("% d", & c);
printf ("sin (% d) =% lf", c, SIN (c));
getchar (); getchar ();
returnera 0;
}

Utförande resultat

Skillnaden mellan sådana makron och funktioner i C-språket är att i sammanställningsfasen ersätts varje förekomst av identifieraren med motsvarande kod. Således kan ett program ha flera kopior av samma kod som motsvarar en identifierare. Om du arbetar med funktioner kommer programmet att innehålla 1 kopia av koden som implementerar den angivna funktionen, och varje gång funktionen kallas till kommer kontrollen att överföras till den.
Du kan avbryta makrodefinitionen med #undef-direktivet.

Man bör dock vara försiktig när man till exempel använder sådana makron

1
2
3
4
5
6
7
8
9
10
11
12
13

#omfatta
#define sum (A, B) A + B
int main ()
{
int a, b, c, d;
a = 3; b = 5;


getchar ();
returnera 0;
}


Utförande resultat:


Som standard ska texten till makrodefinitionen placeras på en rad. Om du behöver överföra texten i en makrodefinition till en ny rad, läggs bakåtstreckstecknet - \ i slutet av den aktuella raden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#omfatta
#define sum (A, B) A + \
B
int main ()
{
int a, b, c, d;
a = 3; b = 5;
c = (a + b) * 2; // c = (a + b) * 2
d = summa (a, b) * 2; // d = a + b * 2;
printf ("a =% d \ n b =% d \ n", a, b);
printf ("c =% d \ n d =% d \ n", c, d);
getchar ();
returnera 0;
}


Dessutom låter #define-direktivet dig ersätta en del av identifieraren. ## används för att ange den del som ska ersättas.

1
2
3
4
5
6
7
8
9

#omfatta
#define SUM (x, y) (a ## x + a ## y)
int main ()
{
int al = 5, a2 = 3;
printf ("% d", SUM (1, 2)); // (a1 + a2)
getchar ();
returnera 0;
}


Utförande resultat:

Direktiven #if eller # ifdef / # ifndef, tillsammans med direktiven #elif, #else och #endif, styr sammanställningen av delar av källfilen.
Om det angivna uttrycket efter #if har ett icke-nollvärde sparas gruppen av rader direkt efter #if-direktivet i transformationsposten. Syntaxen för det villkorliga direktivet är som följer:

1
2
3
4
5
6
7

#om konstant uttryck
grupp av verksamheter
#elif konstant uttryck
grupp av verksamheter
#annan
grupp av verksamheter
#endif


Skillnaden mellan # ifdef / # ifndef-direktiv är att ett konstant uttryck bara kan ställas in med #define.

Varje #if-direktiv i källfilen måste ha ett motsvarande #endif-direktiv. Valfritt antal #elif-direktiv kan placeras mellan #if- och #endif-direktiv, men högst ett #else-direktiv är tillåtet. #Else-direktivet, om det finns, måste vara det sista före #endif-direktivet.

Exempel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#omfatta
#omfatta
#definiera P 2
int main ()
{
system ("chcp 1251");
system ("cls");
#om P == 1
printf ( "Gren 1 pågår");
#elif P == 2
printf ( "Gren 2 pågår, P =% d", P);
#annan
printf ( "En annan gren pågår, P =% d", P);
#endif
getchar ();
returnera 0;
}

Förprocessor det är bäst att betrakta som ett separat program som körs före kompilering. När programmet startar skannar förprocessorn koden uppifrån och ner, fil för fil och letar efter direktiv. DirektivÄr speciella kommandon som börjar med symbolen # och sluta INTE med semikolon. Det finns flera typer av direktiv som vi kommer att titta på nedan.

#Inkludera direktivet

Du har redan sett #include-direktivet i aktion. När du # inkluderar en fil kopierar förprocessorn innehållet i den inkluderade filen till den aktuella filen direkt efter #include-raden. Detta är mycket användbart när du använder vissa data (till exempel funktioner) på flera platser samtidigt.

Direktivet #include har två former:

#omfatta som säger till förprocessorn att leta efter filen i systemvägarna. Du använder oftast det här formuläret när du länkar från C ++ - standardbiblioteken.

#include "filnamn" som säger till förprocessorn att leta efter en fil i den aktuella projektkatalogen. Om det inte finns där kommer förprocessorn att börja kontrollera systemvägarna och alla andra som du angav i dina inställningar. Det här formuläret används för att inkludera anpassade rubrikfiler.

# Definiera direktivet

Direktivet #define kan användas för att skapa makron. Makro- detta är regeln som bestämmer omvandlingen av identifieraren till den angivna informationen.

Det finns två huvudtyper av makron: funktionsmakron och objektmakron.

Makrofunktioner beter sig som funktioner och används för samma ändamål. Vi kommer inte att diskutera dem nu, eftersom deras användning i allmänhet anses vara farlig, och nästan allt de kan göra kan göras med en enkel (linjär) funktion.

Makroobjekt kan bestämmas på något av följande två sätt:

#define identifier
#define identifierare substitution_text

Den övre definitionen har ingen substitution_text, medan den nedre har. Eftersom detta är förbehandlingsdirektiv (och inte enkla) slutar ingen av formerna med semikolon.

Makroobjekt med substitution_text

När förprocessorn stöter på makroobjekt med substitution_text ersätts varje ytterligare förekomst av identifierare med substitution_text. Identifieraren skrivs vanligtvis med stora bokstäver med understrykningar istället för mellanslag.

Tänk på följande kod:

#define MY_FAVORITE_NUMBER 9 std :: cout<< "My favorite number is: " << MY_FAVORITE_NUMBER << std::endl;

#definiera MY_FAVORITE_NUMBER 9

std :: cout<< "My favorite number is: " << MY_FAVORITE_NUMBER << std :: endl ;

Förprocessorn konverterar koden ovan till:

std :: cout<< "My favorite number is: " << 9 << std::endl;

Varje ytterligare förekomst av USE_YEN-identifieraren tas bort och ersätts med "ingenting" (tomt utrymme)!

Detta kan verka ganska värdelöst, men detta är inte huvudsyftet med sådana direktiv. Till skillnad från objektmakron med substitution_text anses denna form av makron vara acceptabel.

Villkorlig sammanställning

Förbehandlingsdirektiven om villkorlig kompilering låter dig bestämma under vilka förhållanden koden kommer att sammanställas och under vilka förhållanden den inte kommer att göra. I den här handledningen tittar vi bara på tre villkorliga sammanställningsdirektiv:

#ifdef;

#ifndef;

#endif.

#Ifdef-direktivet(eng. " om def ined "=" om definierad ") tillåter förprocessorn att kontrollera om värdet tidigare var #define. Om så är fallet kommer koden mellan #ifdef och #endif att kompileras. Om inte, ignoreras koden. Till exempel:

#define PRINT_JOE #ifdef PRINT_JOE std :: cout<< "Joe" << std::endl; #endif #ifdef PRINT_BOB std::cout << "Bob" << std::endl; #endif

#define PRINT_JOE

#ifdef PRINT_JOE

std :: cout<< "Joe" << std :: endl ;

#endif

#ifdef PRINT_BOB

std :: cout<< "Bob" << std :: endl ;

#endif

Eftersom PRINT_JOE redan var #define, std :: cout-linjen<< "Joe" << std::endl; скомпилируется и выполнится. А поскольку PRINT_BOB не был #define, то строчка std::cout << "Bob" << std::endl; не скомпилируется и, следовательно, не выполнится.

#Indef-direktivet(eng. " om n ot def ined "=" om inte definierat ") är den motsatta av #ifdef, som låter dig kontrollera om ett värde har definierats tidigare. Till exempel:

#ifndef PRINT_BOB std :: cout<< "Bob" << std::endl; #endif

#ifndef PRINT_BOB

std :: cout<< "Bob" << std :: endl ;

#endif

Det här kodavsnittet returnerar Bob eftersom PRINT_BOB aldrig har varit #define förut. Villkorlig sammanställning används ofta som rubrikvakter (vi pratar om dem i nästa lektion).

Omfattningen av #define-direktivet

Direktiven körs innan programmet sammanställs: från topp till botten, fil för fil.

Tänk på följande program:

#omfatta void boo () (#define MY_NAME "Alex") int main () (std :: cout<< "My name is: " << MY_NAME; return 0; }

#omfatta

ogiltig boo ()

#define MY_NAME "Alex"

int main ()

std :: cout<< "My name is: " << MY_NAME ;

returnera 0;

Även om #define MY_NAME "Alex" -direktivet definieras i boo-funktionen, kommer förprocessorn inte att märka detta eftersom den inte förstår C ++ -begrepp som funktioner. Därför kommer genomförandet av detta program att vara identiskt med det där #define MY_NAME "Alex" definierades FÖRE eller omedelbart EFTER boo-funktionen. För bättre kodläsbarhet, definiera identifierare (med #define) utanför funktionerna.

När förprocessorn är klar körs alla identifierare (definierade med #define) från den här filen. Detta innebär att direktiv endast är giltiga från definitionspunkten till slutet av filen där de definieras. Direktiv definierade i en kodfil påverkar inte direktiv som definierats i andra filer i samma projekt.

Tänk på följande exempel:

#omfatta ogiltig doSomething () (#ifdef PRINT std :: cout<< "Printing!"; #endif #ifndef PRINT std::cout << "Not printing!"; #endif }

#omfatta

ogiltig doSomething ()

#ifdef SKRIV UT

std :: cout<< "Printing!" ;

#endif

#ifndef PRINT

std :: cout<< "Not printing!" ;

Rubrikfiler ingår i programtexten med förbehandlingsdirektiven#omfatta. Förprocessordirektiv börjar med ett hash-tecken (#), vilket måste vara det allra första tecknet på raden. Programmet som hanterar dessa direktiv kallas förprocessor(i moderna kompilatorer är förprocessorn vanligtvis en del av själva kompilatorn).
#Include-direktivet innehåller innehållet i den angivna filen i programmet. Filnamnet kan anges på två sätt:

#omfatta # inkludera "min_fil.h"

Om filnamnet finns i vinkelparenteser (<>) antas att vi behöver en viss standardhuvudfil, och kompilatorn letar efter den här filen på fördefinierade platser. (Hur dessa platser definieras skiljer sig mycket från plattform till plattform och implementering till implementering.) Dubbla citat indikerar att rubrikfilen är en anpassad rubrikfil och söker efter den från den katalog där programmets källa finns.
Rubrikfilen kan också innehålla #include-direktiv. Därför är det ibland svårt att veta vilka specifika rubrikfiler som ingår i en given källkod, och vissa rubrikfiler kan inkluderas flera gånger. Låt undvika detta villkorliga förbehandlingsdirektiv... Låt oss överväga ett exempel:

#ifndef BOOKSTORE_H #define BOOKSTORE_H / * innehållet i bokhandeln.h-filen * / #endif

#Ifndef villkorliga direktivet kontrollerar om BOOKSTORE_H-värdet tidigare definierades. (BOOKSTORE_H är en förprocessorkonstant; sådana konstanter skrivs vanligtvis med stora bokstäver.) Förprocessorn bearbetar följande rader fram till #endif-direktivet. Annars hoppar den över raderna från #ifndef till # endif.
Direktiv

#define BOOKSTORE_H

definierar förprocessorkonstanten BOOKSTORE_H. Genom att placera detta direktiv direkt efter #ifndef-direktivet kan vi se till att innehållet i bookstore.h-rubrikfilen endast ingår i källtexten, oavsett hur många gånger själva filen ingår i texten.
Ett annat vanligt exempel på att använda villkorliga förprocessordirektiv är införandet av felsökningsinformation i programtexten. Till exempel:

Int main () (#ifdef DEBUG cout<< "Начало выполнения main()\n"; #endif string word; vectortext; while (cin >> word) (#ifdef DEBUG cout<< "Прочитано слово: " << word << "\n"; #endif text.push_back(word); } // ... }

Om DEBUG-konstanten inte är definierad kommer den resulterande programtexten att se ut så här:

Int main () (strängord; vektor text; medan (cin >> word) (text.push_back (word);) // ...)

Annars får vi:

Int main () (cout<< "Начало выполнения main()\n"; string word; vectortext; medan (cin >> word) (cout<< "Прочитано слово: " << word << "\n"; text.push_back(word); } // ... }

Förprocessorkonstanten kan specificeras på kommandoraden när kompilatorn anropas med alternativet -D (olika implementeringar kan kalla detta alternativ annorlunda). För UNIX-system ser kompilatoranropet med definitionen av förbehandlingskonstanten DEBUG så här ut:

$ CC -DDEBUG main.C

Det finns konstanter som automatiskt bestäms av kompilatorn. Vi kan till exempel ta reda på om vi sammanställer ett C ++ - eller C-program. För ett C ++ - program definieras __cplusplus-konstanten (två understrykningar) automatiskt. För standard C definieras __STDC__. Naturligtvis kan båda konstanterna inte definieras samtidigt. Exempel:

#idfef __cplusplus // kompilera ett C ++ - program externt "C"; // extern "C" förklaras i kapitel 7 #endif int main (int, int);

Andra användbara fördefinierade konstanter (i det här fallet är det bättre att säga variabler) av förprocessorn är __LINE__ och __FILE__. Variabeln __LINE__ innehåller numret på den kompilerade raden och __FILE__ är namnet på den kompilerade filen. Här är ett exempel på deras användning:

Om (element_count == 0) cerr<< "Ошибка. Файл: " << __FILE__ << " Строка: " << __LINE__ << "element_count не может быть 0";

De två konstanterna __DATE__ och __TIME__ innehåller sammanställningsdatum och tid.
C-standardbiblioteket tillhandahåller ett användbart makrotillstånd () som söker efter ett tillstånd och, om det misslyckas, ger ett diagnosmeddelande och avbryter programmet. Vi kommer att använda detta användbara makro ofta i efterföljande exempelprogram. För att använda det bör du inkludera direktivet i programmet

#omfatta

assert.h är C-standardbibliotekets rubrikfil. Ett C ++ - program kan hänvisa till en rubrikfil antingen med dess C-namn eller C ++ -namn. I C ++ - standardbiblioteket heter filen cassert. Namnet på rubrikfilen i C ++ - biblioteket skiljer sig från namnet på motsvarande fil för C på grund av frånvaron av .h-förlängningen och bokstaven c införd framför (det nämndes redan ovan att tillägg inte används i sidhuvudfiler för C ++, eftersom de kan bero på implementeringen).
Effekten av att använda #include preprocessor-direktivet beror på typen av huvudfilen. Instruktioner

#omfatta

innehåller innehållet i kassettfilen i programtexten. Men eftersom alla namn som används i C ++ - standardbiblioteket definieras i std-utrymme kommer namnet assert () att vara osynligt tills vi uttryckligen gör det synligt med följande med hjälp av direktivet:

Använda namespace std;

Om vi ​​tar med huvudfilen för C-biblioteket i programmet

#omfatta

då försvinner behovet av ett användningsdirektiv: namnet på assert () kommer att synas ändå. (Namnutrymmen används av biblioteksutvecklare för att förhindra att det globala namnutrymmet störs. I avsnitt 8.5 diskuteras detta ämne mer detaljerat.)