Ce face constexpr
În C, o variabilă const int nu este o „constantă de compilare”: nu poți declara cu ea un tablou global și nici nu o poți folosi în case. De aceea, pentru astfel de valori se foloseau #define sau enum. C23 adaugă constexpr: valoarea este cunoscută la compilare, are un tip verificat și se poate folosi oriunde este nevoie de o constantă.
Inițializarea unui constexpr trebuie să fie o expresie constantă (literali, alte constexpr, sizeof, operații între ele). Dacă folosești o variabilă obișnuită, compilatorul refuză. Valoarea trebuie să încapă exact în tip: constexpr unsigned char x = 300; este eroare, nu trunchiere.
Spre deosebire de C++, în C23 constexpr se aplică doar obiectelor (variabilelor), nu și funcțiilor. Pentru o funcție mică, folosește static inline.
Exemple
Exemplul 1: Dimensiune de tablou și etichete case
NR_ELEVI fixează dimensiunea tabloului global, iar NOTA_MAXIMA apare într-un case. Cu un simplu const int, ambele ar fi dat eroare în C.
#include <stdio.h>
constexpr int NR_ELEVI = 4;
constexpr int NOTA_MAXIMA = 10;
int note[NR_ELEVI] = {10, 6, 9, 10};
int main(void) {
for (int i = 0; i < NR_ELEVI; i++) {
switch (note[i]) {
case NOTA_MAXIMA:
printf("Elevul %d: nota maximă!\n", i + 1);
break;
default:
printf("Elevul %d: %d\n", i + 1, note[i]);
}
}
return 0;
}
Rezultat
Elevul 1: nota maximă!
Elevul 2: 6
Elevul 3: 9
Elevul 4: nota maximă!
Exemplul 2: Constante calculate din alte constante
PRET_CU_TVA este calculat de compilator din alte două constexpr. static_assert verifică la compilare că garanția are cel puțin un an. Atenție: static_assert acceptă doar expresii cu numere întregi, deci nu poate compara direct cele două prețuri double.
#include <stdio.h>
constexpr double PRET_BAZA = 250.0;
constexpr double TVA = 0.21;
constexpr double PRET_CU_TVA = PRET_BAZA * (1 + TVA);
constexpr int ZILE_GARANTIE = 2 * 365;
static_assert(ZILE_GARANTIE >= 365, "garanția minimă este de un an");
int main(void) {
printf("Preț cu TVA: %.2f lei\n", PRET_CU_TVA);
printf("Garanție: %d zile\n", ZILE_GARANTIE);
return 0;
}
Rezultat
Preț cu TVA: 302.50 lei
Garanție: 730 zile
Exemplul 3: Valoarea trebuie să fie cunoscută la compilare
n este o variabilă obișnuită; valoarea ei se știe abia la rulare, deci nu poate inițializa un constexpr.
#include <stdio.h>
int main(void) {
int n = 3;
constexpr int maxim = n * 10;
printf("%d\n", maxim);
return 0;
}
Mesajul compilatorului (programul nu se compilează)
exemplu.c:5:27: error: constexpr variable 'maxim' must be initialized by a constant expression
5 | constexpr int maxim = n * 10;
| ^~~~~~
1 error generated.
Greșeli frecvente
- Scrii
constexpr int dublu(int x) { ... }ca în C++. În C23,constexprnu se aplică funcțiilor. - Crezi că
constșiconstexprsunt același lucru.constînseamnă doar „nu modific valoarea”, care poate veni și de la rulare;constexprcere o valoare cunoscută la compilare. - Inițializezi un
constexprcu o valoare care nu încape în tip (constexpr unsigned char c = 300;). În loc de trunchiere tăcută, primești eroare de compilare.
Comenzi înrudite
const: Marchează o variabilă ca doar pentru citire: compilatorul oprește orice încercare de a o modifica.#define: Definește o macro: un nume pe care preprocesorul îl înlocuiește cu textul dat, înainte ca programul să fie compilat.static_assert: Verifică o condiție la compilare: dacă este falsă, programul nu se compilează și apare mesajul tău.enum: Definește un set de constante întregi cu nume, de exemplu zilele săptămânii sau stările unei comenzi.switch: Alege una din mai multe ramuri după valoarea unui întreg, cu etichete case; fără break, execuția continuă în ramura următoare.Tablouri (array): Un șir de elemente de același tip, așezate unul după altul în memorie și accesate prin index, de la 0.