Директива #define
создает макроподстановку - замену одного фрагмента текста на другой во время фазы препроцессинга. Это чисто текстовая замена, выполняемая до начала компиляции.
#define ИМЯ значение // Простой макрос
#define ИМЯ(параметры) код // Макрос с параметрами
#define PI 3.1415926535
#define MAX_SIZE 100
#define DEBUG_MODE
Как работает:
PI
заменяются на 3.1415926535
DEBUG_MODE
заменяется на... ничего (используется для #ifdef
)#define SQUARE(x) ((x) * (x))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
Как работает:
#define LOG(msg) \
std::cout << __FILE__ << ":" << __LINE__ << " " \
<< msg << std::endl
#
(строковый литерал):#define STRINGIFY(x) #x
// STRINGIFY(hello) → "hello"
##
(конкатенация токенов):#define CONCAT(a, b) a##b
// CONCAT(var, 123) → var123
#define SQUARE(x) x * x
int a = 5;
int b = SQUARE(a++); // Становится a++ * a++ - UB!
#define SUM(a, b) a + b
int res = SUM(1, 2) * 3; // 1 + 2 * 3 = 7 (а не 9)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
MAX(expensiveFunc(), x); // Вызывает expensiveFunc() дважды
#define BAD(x) x * 2
#define GOOD(x) ((x) * 2)
g++ -E file.cpp -o file.ii
g++ -Wall -Wextra ...
#if !defined(MAX_SIZE)
#error "MAX_SIZE must be defined"
#endif
constexpr double PI = 3.1415926535;
inline int square(int x) { return x * x; }
constexpr int max(int a, int b) {
return a > b ? a : b;
}
#define LOG_IF(cond, msg) \
do { \
if (cond) \
std::cout << __FILE__ << ":" << __LINE__ << " " << msg; \
} while(0)
// Использование:
LOG_IF(x > 0, "x is positive: " << x);
Почему do-while? Чтобы требовать точку с запятой и избежать проблем с if-else.
Резюмируем: директива #define
- мощный, но опасный инструмент препроцессора, выполняющий текстовую подстановку. Хотя современный C++ предлагает более безопасные альтернативы, понимание макросов необходимо для работы с legacy-кодом и некоторыми специальными случаями. Всегда предпочитайте constexpr и inline-функции, где это возможно.