Макросы — это инструмент препроцессора, выполняющий текстовую замену в исходном коде до начала компиляции. Они обрабатываются на этапе препроцессинга и принципиально отличаются от функций и других языковых конструкций.
#define PI 3.14159265
#define MAX_SIZE 100
Как работает:
Препроцессор заменяет все вхождения PI на 3.14159265 в коде
#define SQUARE(x) ((x) * (x))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
Особенности:
#define DEBUG // может использоваться для #ifdef
#define LOG(msg) std::cout << __FILE__ << ":" << __LINE__ << " " << msg
Подстановка аргументов
Текстуальная замена параметров переданными значениями
Раскрытие макроса
Замена всего макроса на его определение
Повторное сканирование
Препроцессор проверяет результат на наличие других макросов
Исходный код:
#define MULTIPLY(a, b) a * b
int x = MULTIPLY(2+3, 4+5);
После препроцессинга:
int x = 2+3 * 4+5; // Результат: 19 (а не 45!)
Правильный вариант:
#define MULTIPLY(a, b) ((a) * (b))
#define SQUARE(x) x * x
int y = SQUARE(++x); // превращается в ++x * ++x
#define MAX 100
int MAX_VALUE = 200; // превратится в int 100_VALUE = 200
constexpr double PI = 3.14159265;
inline int square(int x) { return x * x; }
constexpr int max(int a, int b) { return a > b ? a : b; }
Резюмируем: макросы — мощный, но опасный инструмент. В современном C++ их использование следует минимизировать, применяя только там, где без них действительно нельзя обойтись (условная компиляция, логгирование с FILE и т.д.). Для вычислений предпочтительны constexpr и inline-функции.