Препроцессор выполняет обработку исходного кода в несколько этапов:
#include <iostream> // Ищет в системных путях
#include "header.h" // Ищет в текущей директории
Процесс:
#define PI 3.1415926
#define MAX(a,b) ((a) > (b) ? (a) : (b))
Правила подстановки:
#
- строковая конвертация##
- конкатенация токенов#if defined(DEBUG) && DEBUG_LEVEL > 1
// Отладочный код
#elif defined(RELEASE)
// Релизный код
#else
#error "Не определена конфигурация сборки"
#endif
Поддерживаемые условия:
#if
, #ifdef
, #ifndef
#else
, #elif
#endif
#pragma once // Защита от множественного включения
#line 42 "file.cpp" // Изменение нумерации строк
#error "Платформа не поддерживается" // Остановка компиляции
Пример сложной подстановки:
#define CONCAT(a,b) a ## b
#define STRINGIFY(x) #x
int CONCAT(var, 123) = 42; // Становится int var123 = 42;
const char* str = STRINGIFY(Hello); // Становится "Hello"
#define SQUARE(x) x * x
SQUARE(i++); // Становится i++ * i++ - неопределенное поведение
#define MAX 100
int MAX_VALUE = 200; // Становится int 100VALUE = 200;
Как посмотреть результат:
g++ -E source.cpp -o output.ii
clang -E source.cpp -o output.ii
Предкомпилированные заголовки:
g++ -xc++-header header.h -o header.h.gch
Модули C++20:
Встроенные макросы:
__cplusplus // Версия стандарта
__FILE__ // Имя файла
__DATE__ // Дата компиляции
Вывод предупреждений:
g++ -Wall -Wextra source.cpp
Зависимости файлов:
g++ -M source.cpp // Показать зависимости
Сохранить временные файлы:
g++ -save-temps source.cpp
Резюмируем: препроцессор C/C++ выполняет критически важные текстовые преобразования перед компиляцией, включая подключение файлов, условную компиляцию и макроподстановки. Хотя его возможности мощные, они требуют аккуратного использования во избежание тонких ошибок. Современные стандарты C++ предлагают более безопасные альтернативы многим традиционным техникам препроцессинга.