Macro cu parametri în C

Macro care primesc argumente, ca o funcție: textul lor este copiat în locul apelului, cu operatorii # și ## și argumente variabile.

Sintaxă
#define NUME(a, b) (expresie cu (a) și (b))
#define TEXT(x) #x            // transformă în șir
#define LIPESTE(a, b) a##b    // lipește două cuvinte
#define LOG(fmt, ...) printf(fmt __VA_OPT__(,) __VA_ARGS__)

Ce face Macro cu parametri

O macro cu parametri arată ca o funcție, dar nu este una. La #define PATRAT(x) ((x) * (x)), apelul PATRAT(nota) este înlocuit cu textul ((nota) * (nota)). Nu există apel, nu există verificare de tip, iar argumentul este copiat de câte ori apare în definiție.

Pentru că înlocuirea este textuală, pune paranteze în jurul fiecărui parametru și în jurul întregii expresii. Fără ele, PATRAT(2 + 3) devine 2 + 3 * 2 + 3 = 11. Între numele macro-ului și ( nu are voie să fie spațiu, altfel devine o macro simplă.

Operatorul # transformă un argument în șir de caractere (#x → "x"), iar ## lipește două cuvinte într-unul. Cu ... și __VA_ARGS__ (C99) o macro primește oricâte argumente; __VA_OPT__(,) (C23) pune virgula doar dacă există argumente. O macro cu mai multe instrucțiuni se scrie de obicei în do { ... } while (0), ca să se comporte ca o singură instrucțiune.

Parametri

Parametru Descriere
#x Transformă argumentul în șir: TEXT(nota + 1) → "nota + 1".
a##b Lipește cele două bucăți de text într-un singur nume: LIPESTE(nota, 1) → nota1.
... Argumente variabile; în definiție se folosesc prin __VA_ARGS__.
__VA_OPT__(text) C23: pune text doar dacă macro-ul a primit argumente variabile.

Exemple

Exemplul 1: De ce sunt necesare parantezele

PATRAT_GRESIT(2 + 3) devine 2 + 3 * 2 + 3, adică 11. Varianta cu paranteze dă 25, cum te aștepți.

#include <stdio.h>

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

int main(void) {
    printf("Fără paranteze: %d\n", PATRAT_GRESIT(2 + 3));
    printf("Cu paranteze:   %d\n", PATRAT(2 + 3));
    return 0;
}

Rezultat

Fără paranteze: 11
Cu paranteze:   25

Exemplul 2: Operatorii # și ## și o macro de jurnal

AFISEAZA(nota_ana) scrie și numele variabilei, și valoarea ei, datorită lui #. LOG primește un număr variabil de argumente; când nu primește niciunul, __VA_OPT__(,) nu pune virgula, deci printf primește doar formatul.

#include <stdio.h>

#define AFISEAZA(var) printf(#var " = %d\n", var)
#define CAMP(prefix, nume) prefix##nume
#define LOG(fmt, ...) printf("[jurnal] " fmt "\n" __VA_OPT__(,) __VA_ARGS__)

int main(void) {
    int nota_ana = 10;
    int CAMP(nota_, ion) = 8;   // devine: int nota_ion = 8;

    AFISEAZA(nota_ana);
    AFISEAZA(nota_ion);
    LOG("Catalog deschis");
    LOG("Media: %.1f", (nota_ana + nota_ion) / 2.0);
    return 0;
}

Rezultat

nota_ana = 10
nota_ion = 8
[jurnal] Catalog deschis
[jurnal] Media: 9.0

Exemplul 3: Argumentul evaluat de două ori

În MAX(i++, 3) textul i++ apare de două ori în expansiune, deci i crește de două ori. O funcție obișnuită (aici max_int) evaluează argumentul o singură dată.

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))

static int max_int(int a, int b) {
    return a > b ? a : b;
}

int main(void) {
    int i = 5;
    int m = MAX(i++, 3);
    printf("macro:   m = %d, i = %d\n", m, i);

    int j = 5;
    int n = max_int(j++, 3);
    printf("funcție: n = %d, j = %d\n", n, j);
    return 0;
}

Rezultat

macro:   m = 6, i = 7
funcție: n = 5, j = 6

Greșeli frecvente

  • Lași spațiu între nume și paranteză: #define PATRAT (x) ((x)*(x)). Asta definește macro-ul simplu PATRAT cu textul (x) ((x)*(x)).
  • Dai ca argument o expresie cu efecte (i++, un apel de funcție). Dacă parametrul apare de două ori în definiție, efectul se produce de două ori.
  • Scrii o macro cu două instrucțiuni fără do { ... } while (0). Într-un if fără acolade, doar prima instrucțiune ține de if; a doua se execută mereu.
  • Folosești o macro unde merge o funcție static inline. Funcția are tipuri verificate, se poate depana și nu are probleme cu evaluarea dublă.

Comenzi înrudite

  • #define: Definește o macro: un nume pe care preprocesorul îl înlocuiește cu textul dat, înainte ca programul să fie compilat.
  • typeof și auto: typeof dă tipul unei expresii, iar auto deduce tipul variabilei din valoarea inițială. Ambele sunt standard din C23.
  • Funcții și prototipuri: Cum definești și declari funcții în C: tipul rezultatului, parametrii, prototipul și transmiterea argumentelor prin valoare.
  • Funcții variadice (stdarg.h): Funcții cu număr variabil de argumente, ca printf: le citești pe rând cu va_start, va_arg și va_end din stdarg.h.
  • #if, #ifdef, #ifndef: Compilare condiționată: preprocesorul păstrează sau elimină bucăți de cod în funcție de macro definite sau de valoarea lor.
Comunitate & Schimb de cunoștințe

Întrebări & Exemple de Cod: Macro cu parametri

Ai o nelămurire despre utilizarea comenzii Macro cu parametri sau ai descoperit un truc / fragment de cod util? Distribuie-l cu ceilalți programatori!

💬

Fii primul care pune o întrebare sau distribuie un fragment de cod / prompt!

Nu au fost adăugate încă întrebări sau exemple de cod pentru această pagină. Dacă ai întâlnit o problemă sau ai un snippet util, adaugă-l mai jos pentru a-i ajuta pe ceilalți.

Comunitate Adaugă o întrebare sau distribuie un cod

Moderare & Siguranță:

Pentru a menține calitatea și securitatea informațiilor, fiecare întrebare sau fragment de cod/prompt este analizat (manual sau prin moderare asistată de AI) înainte de publicare.