Ce face static_assert
assert verifică o condiție la rulare. static_assert o verifică la compilare: dacă expresia este 0, compilarea se oprește cu eroare. Nu costă nimic la rulare, pentru că după compilare nu mai rămâne nimic din ea.
Expresia trebuie să fie constantă: sizeof, constante constexpr, enum, macro. Se folosește ca să verifici presupuneri despre platformă (sizeof(int) == 4), dimensiunea unei structuri care se scrie pe disc sau se trimite în rețea, ori că un tablou are tot atâtea elemente câte valori are un enum.
În C11 se scria _Static_assert(expresie, "mesaj"), iar static_assert era o macro din <assert.h>. În C23, static_assert este cuvânt cheie și mesajul este opțional.
Exemple
Exemplul 1: Presupuneri despre platformă
Toate verificările sunt adevărate pe calculatorul de build, așa că programul se compilează și rulează. Pe o platformă unde int ar avea alt număr de octeți, compilarea s-ar opri.
#include <stdint.h>
#include <stdio.h>
static_assert(sizeof(int) == 4, "codul presupune int pe 32 de biți");
static_assert(sizeof(int64_t) == 8);
static_assert(-1 >> 1 == -1, "deplasarea la dreapta trebuie să fie aritmetică");
int main(void) {
printf("Toate verificările au trecut la compilare\n");
return 0;
}
Rezultat
Toate verificările au trecut la compilare
Exemplul 2: Tabloul trebuie să aibă un text pentru fiecare valoare din enum
Dacă cineva adaugă o zi în enum și uită textul ei, static_assert oprește compilarea în loc să lase un element lipsă în tablou.
#include <stdio.h>
enum zi { LUNI, MARTI, MIERCURI, JOI, VINERI, NR_ZILE };
static const char *nume_zi[] = {"luni", "marți", "miercuri", "joi", "vineri"};
static_assert(sizeof nume_zi / sizeof nume_zi[0] == NR_ZILE,
"fiecare zi din enum are nevoie de un nume");
int main(void) {
for (int z = LUNI; z < NR_ZILE; z++) {
printf("%d: %s\n", z, nume_zi[z]);
}
return 0;
}
Rezultat
0: luni
1: marți
2: miercuri
3: joi
4: vineri
Exemplul 3: O verificare care nu trece
Pe calculatoarele obișnuite, int are 4 octeți, deci condiția este falsă. Clang arată mesajul și chiar valoarea calculată ('4 == 8').
static_assert(sizeof(int) == 8, "int trebuie să aibă 8 octeți");
int main(void) {
return 0;
}
Mesajul compilatorului (programul nu se compilează)
exemplu.c:1:15: error: static assertion failed due to requirement 'sizeof(int) == 8': int trebuie să aibă 8 octeți
1 | static_assert(sizeof(int) == 8, "int trebuie să aibă 8 octeți");
| ^~~~~~~~~~~~~~~~
exemplu.c:1:27: note: expression evaluates to '4 == 8'
1 | static_assert(sizeof(int) == 8, "int trebuie să aibă 8 octeți");
| ~~~~~~~~~~~~^~~~
1 error generated.
Greșeli frecvente
- Pui în
static_asserto variabilă obișnuită (static_assert(n > 0)). Valoarea ei nu se știe la compilare, deci primești eroare. Pentru verificări la rulare foloseșteassert. - Confunzi
static_assertcuassert:-DNDEBUGdezactiveazăassert, dar nu are niciun efect asupra luistatic_assert.
Comenzi înrudite
assert: Verifică în timpul rulării o condiție care trebuie să fie mereu adevărată și oprește programul cu un mesaj dacă nu este.constexpr: Declară o constantă cu valoare calculată la compilare, cu tip, care poate fi folosită ca dimensiune de tablou sau în static_assert.sizeof: Operatorul care spune câți octeți ocupă un tip sau o variabilă; calculat de compilator, rezultatul are tipul size_t.enum: Definește un set de constante întregi cu nume, de exemplu zilele săptămânii sau stările unei comenzi.#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.