#define în C++

Definește un macro: preprocesorul înlocuiește textual numele cu valoarea lui, peste tot în cod, înainte de compilare.

Sintaxă
#define NUME valoare
#define MACRO(x) ((x) * (x))
#undef NUME

Ce face #define

#define PI 3.14159 spune preprocesorului: „oriunde vezi PI, scrie 3.14159”. Înlocuirea este pur textuală și se face înainte de compilare: macro-urile nu au tip, nu respectă spațiile de nume și nu apar la depanare.

Un macro cu parametri (#define PATRAT(x) ((x) * (x))) arată ca o funcție, dar doar copiază text. De aceea fiecare parametru și întreaga expresie trebuie puse între paranteze. #x transformă parametrul în text, iar #undef NUME șterge definiția.

În C++ modern, pentru constante folosește constexpr, iar pentru „funcții mici” funcții inline/constexpr sau șabloane. #define rămâne util pentru compilare condiționată (#ifdef) și pentru câteva macro-uri predefinite: __cplusplus, __FILE__, __LINE__.

Exemple

Exemplul 1: Constantă și macro predefinit

__cplusplus spune standardul cu care se compilează: 202302 înseamnă C++23.

#include <print>

#define TVA 0.21
#define NUME_MAGAZIN "Librăria Iași"

int main() {
    std::println("{}: preț cu TVA {:.2f} lei", NUME_MAGAZIN, 40 * (1 + TVA));
    std::println("Standardul C++: {}", __cplusplus);
}

Rezultat

Librăria Iași: preț cu TVA 48.40 lei
Standardul C++: 202302

Exemplul 2: Capcana parantezelor

PATRAT_GRESIT(2 + 3) devine textul 2 + 3 * 2 + 3, adică 11, nu 25. Cu paranteze peste tot rezultatul este corect, iar funcția constexpr nu are deloc această problemă.

#include <print>

#define PATRAT_GRESIT(x) x * x
#define PATRAT(x) ((x) * (x))

constexpr int patrat(int x) { return x * x; }

int main() {
    std::println("PATRAT_GRESIT(2 + 3) = {}", PATRAT_GRESIT(2 + 3));
    std::println("PATRAT(2 + 3) = {}", PATRAT(2 + 3));
    std::println("patrat(2 + 3) = {}", patrat(2 + 3));
}

Rezultat

PATRAT_GRESIT(2 + 3) = 11
PATRAT(2 + 3) = 25
patrat(2 + 3) = 25

Exemplul 3: Transformare în text (#) și #undef

#expr pune expresia între ghilimele, așa că macro-ul afișează și codul, și rezultatul. După #undef, numele AFISEAZA nu mai există.

#include <print>

#define AFISEAZA(expr) std::println("{} = {}", #expr, (expr))

int main() {
    int note = 3;
    AFISEAZA(note * 2 + 1);
    AFISEAZA(10 / 4);
#undef AFISEAZA
#ifndef AFISEAZA
    std::println("AFISEAZA nu mai este definit");
#endif
}

Rezultat

note * 2 + 1 = 7
10 / 4 = 2
AFISEAZA nu mai este definit

Greșeli frecvente

  • Pui ; la final: #define MAX 100;. Punctul și virgula ajunge în cod la fiecare folosire (int v[MAX]; devine int v[100;];).
  • Dai unui macro-funcție un argument cu efecte: PATRAT(i++) devine ((i++) * (i++)), deci i crește de două ori (și este comportament nedefinit). Funcțiile nu au această problemă.
  • Numești macro-urile ca pe variabile (#define max 10). Strică orice alt cod care folosește numele max, inclusiv std::max. Convenția este MAJUSCULE pentru macro-uri.

Comenzi înrudite

  • #ifdef, #ifndef, #if, #endif: Compilare condiționată: păstrează sau elimină bucăți de cod înainte de compilare, după ce macro-uri sunt definite.
  • #include: Directivă a preprocesorului care copiază conținutul unui fișier antet în locul ei, ca să poți folosi funcțiile și clasele declarate acolo.
  • constexpr: Cere ca o valoare să fie calculată la compilare; o funcție constexpr poate rula atât la compilare, cât și la rulare.
  • inline: Permite ca o funcție sau variabilă să fie definită în mai multe fișiere (de obicei într-un antet) fără eroare de definiție dublă.