Conditional Compilation

Вне макро-замены важная причина использовать #define состоит в том, чтобы поддержать условную трансляцию. Используя #define, и некоторые другие директивы препроцессора, мы можем проинструктировать компилятор собирать только определенные секции нашего исходного текста. Это полезно при многих обстоятельствах, одно из которых для того, чтобы вставить код отладки, который может быть легко позволен. Ниже мы видим пример, который использует #define, #if, and #endif директивы.

1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: #include <iostream>#include <cstdlib> #define DEBUG using namespace std; int main(int argc, char* argv[]) { #if defined(DEBUG) cerr << "Debugging enabled" << endl;#endif int arr[10]; for (int i = 0; i < 10; i++) { arr[i] = i; #if defined(DEBUG) cerr << "i = " << i << endl; cerr << "arr[i] = " << arr[i] << endl;#endif } return EXIT_SUCCESS;}
Listing 4 Conditional compilation

Директива препроцессора #if работает подобно регулярному if-statement, за исключением того, что она имеет с #endif директивой. Эти две директивы делят секцию исходного текста, который может быть условно собран. Препроцессор оценивает ценность, которая следует #if. Если эта ценность оценивает к true (отличный от нуля), препроцессор включает блок исходного текста. Если это оценивает к false, препроцессор опускает блок исходного текста. В вышеупомянутой распечатке, defined(DEBUG), следует #if директивы. Препроцессор оценивает это к true, только если мы определили идентификатор под названием DEBUG. Так как мы определили DEBUG в линии 4, блоки исходного текста, разделенные #if и #endif, если пары будут собраны. Власть этой техники очевидна, когда мы понимаем все, что мы должны сделать, чтобы повредить код отладки, найденный всюду по программе, удаляют определение DEBUG из программы. Это заставляет препроцессор опускать код отладки.

Условная трансляция также часто используется, чтобы предотвратить многократные определения классов и функций, которые содержатся в файлах заголовка. Включая файл заголовка не раз в программе можно вызвать класс и проблемы переопределения функции. Мы можем предотвратить это используя условную трансляцию. Ниже по линии 1 #if директива имела обыкновение проверять, определила ли программа идентификатор _PERSON_H_. Если это не было определено, то остальная часть исходного текста в примере обработана. Если это было определено, исходный текст пропускается препроцессором. Ключ к этой технике в line 2, где программа определяет _PERSON_H_. Если бы у нас была программа, у которой было несколько файлов исходного текста, что все включали следующий файл заголовка, то условная трансляция гарантировала бы, что содержание файла включено только однажды. В первый раз файл был включен, приведет к определению _PERSON_H _, который тогда предотвратил бы включение содержания файла во второй раз.

1: 2: 3: 4: 5: 6: 7: 8: 9: #if !defined(_PERSON_H_)#define _PERSON_H_ class Person { // Class declaration...}; #endif
Listing 5 Preventing multiple declarations

Сокращенные конструкции условной трансляции существуют, который мы можем использовать вместо defined оператора. Директива #ifdef identifier эквивалентна #if defined(identifier). Аналогично, директива #ifndef identifier is equivalent to #if !defined(identifier).