Směrnice si. Makro preprocesoru __FILE__. direktivy #if a #endif

#zahrnout

Direktiva #include vloží kód z zadaný soubor k aktuálnímu souboru, tedy pouhým připojením jiného souboru, můžeme využívat jeho funkce, třídy a proměnné. Soubory záhlaví jsou obvykle umístěny buď v aktuálním adresáři, nebo ve standardním systémovém adresáři.

Zahrnutí hlavičkových souborů se provádí v době kompilace nebo jako soubor, který je součástí vašeho projektu. Tato funkce závisí na konkrétní implementaci vašeho kompilátoru, takže pro více informací podrobné informace, projděte si nastavení kompilátoru.

Pokud není soubor začlenění nalezen, proces kompilace selže s chybou.

#define direktiva

Direktiva #define má dvě podoby:

  • definice konstant;
  • definice maker.
Definice konstant
#define nameHodnota tokenu

Při použití konstanty name - nameToken , bude nahrazena hodnotou value , tedy zhruba řečeno, jedná se o stejnou proměnnou, jejíž hodnotu nelze změnit. Podívejme se na příklad použití konstanty:

#zahrnout #define TEXT "Mars" // definice konstanty int main() ( std::cout<< TEXT; return 0; }

Jak vidíte, pro přístup k hodnotě konstanty jednoduše použijeme její název.

Definování parametrizovaných maker

#define nameMacros(arg1, arg2, ...) výraz

Definujme například makro, které vrátí maximálně dvě hodnoty.

#define MAX(číslo1, číslo2) ((číslo1) > (číslo2) ? (číslo1) : (číslo2))

Pozor, pro definování víceřádkového makra musí mít každý řádek na konci symbol, který sděluje preprocesoru, že makro ještě nebylo dokončeno.

směrnice #undef

Direktiva #undef přepíše konstantní nebo preprocesorové makro dříve definované pomocí direktivy #define.

#undef názevToken

Podívejme se na příklad použití direktivy #undef:

#define E 2.71828 // dříve definované makro int sumE = E + E; // volání makra #undef E // nyní E není makro

Direktiva #undef se obvykle používá k odstranění dříve definované konstanty nebo makra z malé oblasti programu. To se provádí tak, že pro celý program makro nebo konstanta zůstává, ale pro určitou oblast lze stejné makro nebo konstantu předefinovat. Bylo by nebezpečné předefinovat konstantu v celém programu, ale v krátké oblasti je to relativně bezpečné. Direktiva #undef je jediný způsob, jak vytvořit tento rozsah, protože rozsah maker nebo konstant sahá od #define po #undef .

direktiva #if

#if value // kód, který bude proveden, pokud je hodnota true #elsif hodnota1 // tento kód bude proveden, pokud bude hodnota1 true #else // kód, který bude proveden jinak #endif

Direktiva #if zkontroluje, zda je hodnota true, a pokud ano, provede kód, který je před závěrečnou direktivou #endif. Jinak se kód uvnitř #if nezkompiluje, bude odstraněn kompilátorem, ale to neovlivní zdrojový kód ve zdroji.

Vezměte prosím na vědomí, že #if může mít vnořené direktivy #elsif a #else. Níže je uveden příklad kódu pro komentování bloků kódu pomocí následující konstrukce:

#if 0 // kód, který je třeba zakomentovat #endif

Pokud máte ve svém programu bloky kódu, které obsahují víceřádkové komentáře a potřebujete celý tento blok kódu zabalit do komentáře, nic nebude fungovat, pokud použijete /* víceřádkový komentář*/ . Další věcí je konstrukce direktiv #if #endif.

direktiva #ifdef

#ifdef nameToken // kód, který bude spuštěn, pokud je definován nameToken #else // kód, který bude proveden, pokud nameToken není definován #endif

Direktiva #ifdef kontroluje, zda makro nebo symbolická konstanta byla dříve definována jako #define . Pokud ano, kompilátor zahrne do programu kód, který je mezi direktivami #ifdef a #else, pokud nameToken nebyl dříve definován, provede se kód mezi #else a #endif, nebo pokud neexistuje #else kompilátor okamžitě přejde na # endif. Například makro __cpp je definováno v C++, ale ne v C. Tuto skutečnost můžete využít ke smíchání kódu C a C++ pomocí direktivy #ifdef:

#ifdef __cpp // C++ kód #else // C kód #endif

direktiva #ifndef

#ifndef nameToken // kód, který bude spuštěn, pokud nameToken není definován #else // kód, který bude proveden, pokud je definován nameToken #endif

Direktiva #ifndef kontroluje, zda makro nebo symbolická konstanta byla dříve definována jako #define . Pokud ano, kompilátor zahrne do programu kód, který je mezi direktivami #else a #endif, pokud nameToken nebyl dříve definován, provede se kód mezi #ifndef a #else, nebo pokud neexistuje #else kompilátor okamžitě přejde na # endif. Direktivu #ifndef lze použít k zahrnutí hlavičkových souborů. pokud nejsou připojeny, použijte k tomu symbolickou konstantu jako indikátor funkčnosti spojené s projektem.

Například v hlavičkový soubor Existuje rozhraní třídy, které je třeba připojit k projektu, pokud tato třída nebyla připojena dříve.

#ifndef PRODUCT_H #define PRODUCT_H class Produkt ( // kód třídy... ); #endif PRODUCT_H

V tomto případě se použije prázdný znaková konstanta PRODUCT_H, který lze definovat pouze v programu společně s třídou Product. Pokud tedy zjistíme, že konstanta PRODUCT_H je již definována, pak je třída také a pak odstraníme předefinování třídy, což může vést k překryvné chybě.

#chybová směrnice

#error "Tento kód by se neměl zkompilovat"

Direktiva #error umožňuje zobrazit zprávu v seznamu chyb kompilace, pokud dojde k odpovídající chybě. Tato direktiva je nejužitečnější při použití v kombinaci s direktivami #if , #elsif , #else ke kontrole kompilace, pokud některá podmínka není pravdivá. Například:

#ifndef __unix__ // __unix__ je obvykle podporován na systémech Unix #error "Podporováno pouze na Unix" #endif

Makro preprocesoru __FILE__

Makro preprocesoru __FILE__ se rozšíří na úplnou cestu k aktuálnímu souboru (zdroji). __FILE__ je užitečný pro vytváření souboru protokolu, generování chybových zpráv pro programátory a ladění kódu.

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

Makro __FILE__ se často používá ve spojení s makrem __LINE__, které poskytuje aktuální číslo řádku.

Makro preprocesoru __LINE__

Makro __LINE__ se nahradí aktuálním číslem řádku ve zdrojovém souboru jako celočíselná hodnota. __LINE__ je užitečné při vytváření souboru protokolu nebo generování chybových zpráv o číslech řádků pro programátory k ladění kódu.

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

Makro __LINE__ se často používá ve spojení s makrem __FILE__, které zobrazuje adresu aktuálního zdrojového souboru.

Makro preprocesoru __DATE__

Makro __DATE__ se nahradí aktuálním datem (časem kompilace) jako [mmm dd rrrr] (například „7. prosince 2012″) jako řetězec. __DATE__ lze použít k poskytnutí informací o čase kompilace.

Cout<< __DATE__ << endl;

Můžete také použít makro __TIME__ k získání aktuálního času kompilace.

Makro preprocesoru __TIME__

Makro __TIME__ se rozšíří v aktuálním čase (čas kompilace) ve formátu hh:mm:cc ve 24hodinovém formátu (například „22:29:12″). Makro __TIME__ lze použít k poskytnutí časové informace v určitém bodě kompilace.

Cout<< __TIME__ << endl;

Makro preprocesoru __TIMESTAMP__

Makro __TIMESTAMP__ se rozšíří v aktuálním čase (čas kompilace) ve formátu Ddd Mmm Datum hh::mm::ss rrrr, čas ve 24hodinovém formátu:

  • Ddd je zkratka pro den v týdnu.
  • mmm toto je zkrácený měsíc,
  • Datum — aktuální den v měsíci (1-31),
  • yyyy je čtyřmístný rok.

Například „Pá 7. prosince 00:42:53 2012“ . Makro __TIMESTAMP__ lze použít k získání informací o datu a čase kompilace.

Cout<< __TIMESTAMP__ << endl;

Můžete také použít makro __TIME__ k získání aktuálního času kompilace a makro __DATE__ k získání data.

směrnice #pragma

#pragma rozšíření specifické pro kompilátor

Direktiva #pragma se používá pro přístup k rozšířením specifickým pro kompilátor. Použití direktivy #pragma spolu s tokenem jednou požádá kompilátor, aby zahrnul hlavičkový soubor pouze jednou, bez ohledu na to, kolikrát je importován:

#pragma Once // hlavičkový soubor

V tomto příkladu direktiva #pragma Once zabraňuje tomu, aby byl soubor vícekrát zahrnut do projektu, tj. zabraňuje přepsání.

Direktivu #pragma lze použít i pro jiné účely, například #pragma se obvykle používá k potlačení varování. Například v MVS:

#pragma varování (zakázat: 4018)

Direktiva #pragma v tomto příkladu slouží k potlačení varování 4018 Další použití direktivy #pragma naleznete v dokumentaci kompilátoru.

Makro operátor #

#

Operátor # vloží textový token do řetězce v uvozovkách. Podívejme se na příklad:

#zahrnout pomocí jmenného prostoru std; #define zprávy cout<< "Сообщение: " #s << endl; int main() { message("GunGame"); return 0; }

Provede se zřetězení řetězců a makro zprávy se rozšíří na cout<< "Сообщение: GunGamen"; . Обратите внимание на то, что операция # должна использоваться совместно с аргументами, так как # ссылается на аргумент.

Makro operátor ##

Operátor ## vezme dva samostatné tokeny a slepí je dohromady do jednoho makra. Výsledkem může být název proměnné, název třídy nebo jakýkoli jiný identifikátor. Například:

#define type ch##ar typ a; // proměnná a je datový typ char, protože ch a ar jsou sloučeny do char

Podívejme se na další příklad použití operátoru ##, ve kterém kombinujeme dva tokeny:

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

Když program zavolá toto makro, dva tokeny se spojí do jednoho. Operace ## musí mít dva operandy.

P.S.: Každý seriózní program musí mít vlastní databázi, obvykle se ke správě databáze používají následující DBMS: MySQL, MsSQL, PostgreeSQL, Oracle atd. Při instalaci sql serveru pro vás bude nepostradatelným pomocníkem fórum na cyberforum.ru; . Zeptejte se na tomto fóru, určitě vám pomohou při řešení vašeho problému.

Soubory záhlaví jsou součástí textu programu pomocí direktivy preprocesoru#zahrnout. Direktivy preprocesoru začínají ostrým znakem (#), což musí být úplně první znak řádku. Program, který tyto direktivy zpracovává, se nazývá preprocesor(v moderních kompilátorech je preprocesor obvykle součástí samotného kompilátoru).
Direktiva #include zahrnuje obsah zadaného souboru do programu. Název souboru lze zadat dvěma způsoby:

#zahrnout #include "muj_soubor.h"

Pokud je název souboru uzavřen v lomených závorkách (<>), předpokládá se, že potřebujeme nějaký standardní hlavičkový soubor a překladač hledá tento soubor na předem definovaných místech. (Způsob, jakým jsou tato umístění definována, se mezi platformami a implementacemi značně liší.) Dvojité uvozovky označují, že soubor záhlaví je vlastní soubor záhlaví a je vyhledáván v adresáři, kde je umístěn zdrojový kód programu.
Soubor záhlaví může také obsahovat direktivy #include. Proto je někdy obtížné pochopit, které konkrétní soubory záhlaví jsou zahrnuty v daném zdrojovém kódu, a některé soubory záhlaví mohou být zahrnuty více než jednou. Tomu se lze vyhnout podmíněné direktivy preprocesoru. Podívejme se na příklad:

#ifndef BOOKSTORE_H #define BOOKSTORE_H /* obsah souboru knihkupectví.h */ #endif

Podmíněná direktiva #ifndef kontroluje, zda byla již dříve definována hodnota BOOKSTORE_H. (BOOKSTORE_H je konstanta preprocesoru; takové konstanty se obvykle píší velkými písmeny.) Preprocesor zpracovává následující řádky až po direktivu #endif. Jinak přeskakuje řádky z #ifndef do #endif.
Směrnice

#define KNIHOCHOD_H

definuje konstantu preprocesoru BOOKSTORE_H. Umístěním této direktivy bezprostředně za direktivu #ifndef můžeme zajistit, že obsah hlavičkového souboru bookstore.h bude zahrnut do zdrojového textu pouze jednou, bez ohledu na to, kolikrát bude samotný soubor v textu zahrnut.
Dalším běžným příkladem použití podmíněných direktiv preprocesoru je zahrnutí informací o ladění do textu programu. Například:

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

Pokud konstanta DEBUG není definována, výsledný text programu bude vypadat takto:

Int main() (řetězcové slovo; vektor text; while (cin >> slovo) ( text.push_back(word); ) // ... )

Jinak dostaneme:

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

Konstantu preprocesoru lze zadat na příkazovém řádku při volání kompilátoru pomocí volby -D (tato volba může být v různých implementacích pojmenována jinak). U systémů UNIX vypadá volání kompilátoru s definicí konstanty preprocesoru DEBUG takto:

$CC -DDEBUG main.C

Existují konstanty, které jsou automaticky určeny kompilátorem. Můžeme například zjistit, zda kompilujeme program v C++ nebo C. Pro program v C++ je automaticky definována konstanta __cplusplus (dvě podtržítka). Pro standardní C je definován __STDC__. Přirozeně nelze definovat obě konstanty současně.

Příklad:

#idfef __cplusplus // kompilace programu C++ extern "C";

// extern "C" vysvětleno v kapitole 7 #endif int main(int,int);<< "Ошибка. Файл: " << __FILE__ << " Строка: " << __LINE__ << "element_count не может быть 0";

Další užitečné předdefinované konstanty preprocesoru (v tomto případě proměnné) jsou __LINE__ a __FILE__. Proměnná __LINE__ obsahuje číslo aktuálního kompilovaného řádku a __FILE__ je název kompilovaného souboru. Zde je příklad jejich použití:
Jestliže (počet_prvků == 0) cerr

#zahrnout

asse.h je soubor záhlaví standardní knihovny C. Program C++ může odkazovat na soubor záhlaví buď svým jménem C nebo názvem C++. Ve standardní knihovně C++ se tento soubor nazývá cassert. Název hlavičkového souboru v knihovně C++ se liší od názvu odpovídajícího souboru pro C v nepřítomnosti přípony .h a písmeno c je umístěno vpředu (již výše bylo zmíněno, že v hlavičkových souborech se přípony nepoužívají pro C++, protože mohou být závislé na implementaci).
Účinek použití direktivy preprocesoru #include závisí na typu hlavičkového souboru. Instrukce

#zahrnout

obsahuje obsah kazety se soubory. Ale protože všechna jména používaná ve standardní knihovně C++ jsou definována v prostoru std, bude název statement() neviditelný, dokud jej explicitně nezviditelníme pomocí následující direktivy using:

Použití jmenného prostoru std;

Pokud do programu zahrneme hlavičkový soubor pro knihovnu C

#zahrnout

pak není potřeba žádná direktiva using: jméno asse() bude stejně viditelné.

(Jmenné prostory používají vývojáři knihoven, aby zabránili globálnímu znečištění jmenného prostoru. Část 8.5 pojednává o tomto tématu podrobněji.) V tomto článku budeme pokračovat v chápání umění programování v C++. V tomto bodě vašeho školení je čas seznámit se s věcmi, jako jsou direktivy preprocesoru. Při pohledu do budoucna řeknu, že v předchozích lekcích jsme směrnici již používali#zahrnout

, který se používá k zahrnutí hlavičkových souborů.

Nejprve si definujme, co je to preprocesor. Kompilace jakéhokoli programu probíhá v několika fázích a jednou z prvních je zpracování preprocesorem. Jednoduše řečeno, preprocesor je program, který čte zdrojový kód programu a upravuje jej na základě direktiv. Schematicky lze celý proces vytváření programu znázornit následovně.

Jak vidíte, před kompilací je zdrojový text programu zpracován preprocesorem, pojďme se blíže podívat na jeho instrukce.

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

#zahrnout

Pokud je název souboru uzavřen v lomených závorkách, pak preprocesor hledá soubor v předdefinovaném umístění. Použití dvojitých závorek zahrnuje zahrnutí souboru ze stejného adresáře, kde je umístěn zdrojový kód zkompilovaného programu. Za zmínku také stojí, že zahrnuté soubory mohou také obsahovat direktivy preprocesoru, zejména direktivu #include, takže mohou nastat problémy s více zahrnutím stejného souboru. Aby se předešlo tomuto druhu zmatku, byly zavedeny podmíněné směrnice, podívejme se na příklad jejich použití:

#ifndef CUCUMBLER_H

#define CUCUMBLER_H

/* obsah souboru cucumbler.h */

Direktiva #ifndef zkontroluje, zda již byla dříve definována konstanta CUCUMBLER_H, a pokud je odpověď záporná, provede se definice této konstanty a dalšího kódu, který následuje před direktivou #endif. Jak asi tušíte, direktiva #define definuje konstantu CUCUMBLER_H. V tomto případě takový kus kódu pomáhá vyhnout se opakovanému zahrnutí stejného kódu, protože po prvním zahrnutí se inicializuje konstanta CUCUMBLER_H a následné #ifndef kontroly CUCUMBLER_H vrátí hodnotu FALSE.

Direktiva #define je také široce používána při ladění programu.

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

pomocí jmenného prostoru std;

cout<< "Начало функции main()\n";

vektor text_array;

zatímco (cin >> text)

cout<< "Прочитан текст: " << text << "\n";

text_array.push_back(text);

Pokud konstanta IN_DEBUG není zadána, preprocesor vygeneruje následující zdroj:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

pomocí jmenného prostoru std;

vektor text_array;

zatímco (cin >> text)

text_array.push_back(text);

Ale pokud definujete IN_DEBUG, text programu se radikálně změní

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

pomocí jmenného prostoru std;

cout<< "Начало функции main()\n";

vektor text_array;

zatímco (cin >> text)

cout<< "Прочитан текст: " << text << "\n";

text_array.push_back(text);

Konstantu preprocesoru můžete nastavit přímo z konzoly. Například kompilátor g++ používá následující formát

Preprocesor je speciální program, který je součástí kompilátoru jazyka C. Je určen pro předběžné zpracování programového textu. Preprocesor umožňuje zahrnout soubory do textu programu a zadat definice maker.
Práce preprocesoru se provádí pomocí speciálních direktiv (instrukcí). Jsou označeny křížkem #. Na konci řádků označujících direktivy v jazyce C se středník umisťovat nemusí.

Základní direktivy preprocesoru

#include - vloží text ze zadaného souboru
#define - určuje definici makra (makro) nebo symbolickou konstantu
#undef - zruší předchozí definici
#if - provede podmíněnou kompilaci, když je konstantní výraz pravdivý
#ifdef - provádí podmíněnou kompilaci, když je definována symbolická konstanta
#ifndef - provádí podmíněnou kompilaci, když symbolická konstanta není definována
#else - větev podmíněné kompilace, když je výraz nepravdivý
#elif - větev podmíněné kompilace vzniklá sloučením else a if
#endif - konec větve podmíněné kompilace
#line - preprocesor změní aktuální číslo řádku a název kompilovaného souboru
#error - vydává diagnostickou zprávu
#pragma - akce, která závisí na konkrétní implementaci kompilátoru.

#include směrnice

Direktiva #include vám umožňuje zahrnout určený soubor do textu programu. Pokud je soubor standardní knihovnou a je ve složce kompilátoru, je uzavřen v lomených závorkách<> .
Pokud je soubor v aktuálním adresáři projektu, je uveden v uvozovkách "" . U souboru umístěného v jiném adresáři musíte zadat úplnou cestu v uvozovkách.

#zahrnout
#include "func.c"

#define direktiva

Direktiva #define umožňuje vkládat do textu programu konstanty a definice maker.
Obecný záznamový formulář

#define Náhrada identifikátoru


Pole Identifikátor A Nahrazení oddělené jednou nebo více mezerami.
Direktiva #define říká kompilátoru, aby nahradil řetězec určený argumentem Nahrazení místo každého argumentu Identifikátor ve zdrojovém souboru. Identifikátor není nahrazen, pokud je v komentáři, na řádku nebo jako součást delšího identifikátoru.

1
2
3
4
5
6
7
8

#zahrnout
#definovat A 3
int main()
{
printf("%d + %d = %d" , A, A, A+A); // 3 + 3 = 6
getchar();
návrat 0;
}

V závislosti na hodnotě konstanty jí kompilátor přiřadí jeden nebo druhý typ. K předefinování typu konstanty můžete použít přípony:

  • U nebo u představuje celočíselnou konstantu ve tvaru bez znaménka;
  • F (nebo f ) umožňuje popsat skutečnou konstantu typu float ;
  • L (nebo l ) umožňuje přidělit 8 bajtů celočíselné konstantě (long int);
  • L (nebo l ) umožňuje popsat skutečnou konstantu typu long double

#define A 280U // unsigned int
#define B 280LU // unsigned long int
#define C 280 // int (long int)
#define D 280L // long int
#define K 28.0 // double
#define L 28.0F // plovoucí
#define M 28,0L // dlouhý dvojitý

Druhá forma syntaxe definuje funkční makro s parametry. Tento formulář umožňuje volitelný seznam parametrů, které musí být uvedeny v závorkách. Po definování makra každý následující výskyt

identifikátor(argument1, ..., argumentn)


nahrazena verzí argumentu nahrazení, ve kterém jsou skutečné argumenty nahrazeny formálními argumenty.

Příklad v C: Výpočet sinusu úhlu

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

#zahrnout
#zahrnout
#zahrnout
#define PI 3.14159265
#define SIN(x) sin(PI*x/180)
int main()
{
int c;
system("chcp 1251" );
system("cls" );
printf( "Zadejte úhel ve stupních: ");
scanf("%d" , atd);
printf("sin(%d)=%lf" , c, SIN(c));
getchar(); getchar();
návrat 0;
}

Výsledek provedení

Rozdíl mezi takovými definicemi maker a funkcemi v jazyce C je ten, že ve fázi kompilace je každý výskyt identifikátoru nahrazen odpovídajícím kódem. Program tedy může mít více kopií stejného kódu odpovídajících identifikátoru. V případě práce s funkcemi bude program obsahovat 1 instanci kódu, který implementuje zadanou funkci a při každém přístupu k funkci se na ni přenese řízení.
Makro můžete zrušit pomocí direktivy #undef.

Při používání takových definic maker je však třeba postupovat opatrně, např.

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

#zahrnout
#define součet(A,B) A+B
int main()
{
int a, b, c, d;
a = 3; b = 5;


getchar();
návrat 0;
}


Výsledek provedení:


Ve výchozím nastavení by měl být text definice makra na jednom řádku. Pokud chcete přesunout text definice makra na nový řádek, vložte na konec aktuálního řádku znak zpětného lomítka - \ .

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

#zahrnout
#define součet(A,B) A + \
B
int main()
{
int a, b, c, d;
a = 3; b = 5;
c = (a + b) * 2; // c = (a + b)*2
d = součet (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();
návrat 0;
}


Direktiva #define navíc umožňuje nahradit část identifikátoru. ## se používá k označení dílu, který má být vyměněn.

1
2
3
4
5
6
7
8
9

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


Výsledek provedení:

Direktivy #if nebo #ifdef/#ifndef spolu s direktivami #elif , #else a #endif řídí kompilaci částí zdrojového souboru.
Pokud je zadaný výraz za #if nenulový, je v záznamu převodu uložena skupina řádků bezprostředně následujících za direktivou #if. Syntaxe podmíněné směrnice je následující:

1
2
3
4
5
6
7

#-li konstantní výraz
operační skupina
#elif konstantní výraz
operační skupina
#jiný
operační skupina
#endif


Rozdíl mezi direktivami #ifdef/#ifndef je v tom, že konstantní výraz lze zadat pouze pomocí #define .

Každá direktiva #if ve zdrojovém souboru musí mít odpovídající závěrečnou direktivu #endif. Mezi direktivami #if a #endif se může objevit libovolný počet direktiv #elif, ale není povoleno více než jedna direktiva #else. Direktiva #else, pokud existuje, musí být poslední před direktivou #endif.

Příklad

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

#zahrnout
#zahrnout
#definujte P 2
int main()
{
system("chcp 1251" );
system("cls" );
#-li P==1
printf( "Pobočka 1 běží");
#elif P==2
printf( "Pobočka 2 probíhá, P=%d", P);
#jiný
printf( "Běží další větev, P=%d", P);
#endif
getchar();
návrat 0;
}

Preprocesor nejlépe si jej představit jako samostatný program, který se spustí před kompilací. Když program běží, preprocesor skenuje kód shora dolů, soubor po souboru, a hledá direktivy. směrnice jsou speciální příkazy začínající symbolem # a NEKONČETE středníkem. Existuje několik typů direktiv, na které se podíváme níže.

#include směrnice

Už jste viděli direktivu #include v akci. Když #include soubor, preprocesor zkopíruje obsah obsaženého souboru do aktuálního souboru ihned po řádku #include. To je velmi užitečné při používání určitých dat (například funkcí) na několika místech najednou.

Direktiva #include má dvě podoby:

#zahrnout , který říká preprocesoru, aby hledal soubor v systémových cestách. Nejčastěji tento formulář využijete při připojování ze standardních C++ knihoven.

#include "název souboru", který říká preprocesoru, aby hledal soubor v aktuálním adresáři projektu. Pokud tam není, preprocesor začne kontrolovat systémové cesty a všechny další, které jste zadali v nastavení. Tento formulář se používá k zahrnutí vlastních záhlaví souborů.

#define direktiva

Direktivu #define lze použít k vytvoření maker. Makro je pravidlo, které určuje převod identifikátoru na specifikovaná data.

Existují dva hlavní typy maker: funkční makra a objektová makra.

Makro funkce se chovají jako funkce a používají se ke stejným účelům. Nyní je nebudeme rozebírat, protože jejich použití je obecně považováno za nebezpečné a téměř vše, co umí, lze provést jednoduchou (lineární) funkcí.

Objektová makra lze určit jedním z následujících dvou způsobů:

#definujte identifikátor
#define identifikátor substituční_text

Horní definice nemá žádný substitution_text , zatímco spodní ano. Protože se jedná o direktivy preprocesoru (a ne jednoduché), žádný z formulářů nekončí středníkem.

Makro objekty s substitučním_textem

Když preprocesor narazí na makro objekty s textem_substituce, všechny další výskyty identifikátoru jsou nahrazeny textem_substituce. Identifikátor se obvykle píše velkými písmeny s podtržítky místo mezer.

Zvažte následující fragment kódu:

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

#define MY_FAVORITE_NUMBER 9

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

Preprocesor převede výše uvedený kód na:

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

Jakýkoli další výskyt identifikátoru USE_YEN je odstraněn a nahrazen „nic“ (prázdné místo)!

To se může zdát poněkud neužitečné, to však není hlavním účelem těchto směrnic. Na rozdíl od objektových maker s textem_substituce je tato forma makra považována za přijatelnou pro použití.

Podmíněná kompilace

Direktivy preprocesoru podmíněné kompilace umožňují určit, za jakých podmínek se kód zkompiluje a za jakých ne. V tomto tutoriálu se podíváme pouze na tři direktivy podmíněné kompilace:

#ifdef;

#ifndef;

#endif.

direktiva #ifdef(anglicky " pokud def ined" = "pokud je definováno") umožňuje preprocesoru zkontrolovat, zda byla hodnota #definována dříve. Pokud ano, pak se zkompiluje kód mezi #ifdef a #endif. Pokud ne, kód bude ignorován. Například:

#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

Protože PRINT_JOE již byl #define, řádek std::cout<< "Joe" << std::endl; скомпилируется и выполнится. А поскольку PRINT_BOB не был #define, то строчка std::cout << "Bob" << std::endl; не скомпилируется и, следовательно, не выполнится.

direktiva #ifndef(anglicky " pokud n ot def ined" = "pokud není definováno") je přesným opakem #ifdef, který umožňuje zkontrolovat, zda hodnota nebyla dříve definována. Například:

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

#ifndef PRINT_BOB

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

#endif

Výsledkem spuštění této části kódu bude Bob , protože PRINT_BOB nikdy předtím nebyl #define. Podmíněná kompilace se velmi často používá jako ochrana hlaviček (budeme si o nich povídat v další lekci).

#define rozsah direktivy

Direktivy se provádějí před kompilací programu: shora dolů, soubor po souboru.

Zvažte následující program:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include: void boo() ( #define MY_NAME "Alex" ) int main() ( std::cout<< "My name is: " << MY_NAME; return 0; }

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

void boo()

#define MY_NAME "Alex"

int main()

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

návrat 0;

I když je direktiva #define MY_NAME "Alex" definována uvnitř funkce boo, preprocesor si toho nevšimne, protože nerozumí konceptům C++, jako jsou funkce. Proto bude provádění tohoto programu totožné s tím, ve kterém bylo #define MOJE_JMÉNO "Alex" definováno PŘED nebo bezprostředně PO funkci boo. Pro lepší čitelnost kódu definujte identifikátory (pomocí #define) vnějších funkcí.

Poté, co preprocesor dokončí své provádění, všechny identifikátory (definované pomocí #define) z tohoto souboru jsou zahozeny. To znamená, že direktivy jsou platné pouze od bodu jejich definice do konce souboru, ve kterém jsou definovány. Direktivy definované v jednom souboru kódu nemají vliv na direktivy definované v jiných souborech ve stejném projektu.

Zvažte následující příklad:

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include: void doSomething() ( #ifdef PRINT std::cout<< "Printing!"; #endif #ifndef PRINT std::cout << "Not printing!"; #endif }

Začněme direktivou #include, kterou nahradí preprocesor s obsahem souboru, který za ním následuje. Příklad použití #include:

void doSomething()

#ifdef TISKNOUT

std::cout<< "Printing!" ;

#endif

#ifndef TISKNOUT

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




Nahoru