Ce face Atribute [[...]]
Un atribut se scrie între paranteze pătrate duble, înaintea declarației: [[nodiscard]] int salveaza(void);. Atributele nu schimbă ce face programul; ele îi spun compilatorului ce intenționezi, ca să te avertizeze când codul nu respectă intenția. C23 a standardizat sintaxa (luată din C++), înlocuind extensiile vechi de tipul __attribute__((...)).
Atributele standard: [[nodiscard]] (avertisment dacă rezultatul funcției este ignorat), [[maybe_unused]] (fără avertisment dacă variabila sau parametrul nu este folosit), [[deprecated]] (avertisment la fiecare folosire, cu mesaj opțional), [[fallthrough]] (trecerea intenționată la următorul case), [[noreturn]] (funcția nu se mai întoarce, de exemplu apelează exit). Mai există [[unsequenced]] și [[reproducible]], pentru optimizarea funcțiilor fără efecte.
Disponibilitatea unui atribut se verifică cu __has_c_attribute(nume). Un compilator ignoră atributele pe care nu le cunoaște (cu un avertisment).
Exemple
Exemplul 1: maybe_unused și fallthrough
Cu -Wall -Wextra -Werror, un parametru nefolosit și o trecere neanunțată la alt case ar opri compilarea. Atributele spun că ambele sunt intenționate, așa că programul se compilează fără avertismente.
#include <stdio.h>
static void raport(int zi, [[maybe_unused]] const char *autor) {
switch (zi) {
case 5:
printf("Vineri: trimite raportul săptămânal\n");
[[fallthrough]];
case 1:
case 2:
case 3:
case 4:
printf("Zi lucrătoare (%d)\n", zi);
break;
default:
printf("Weekend (%d)\n", zi);
}
}
int main(void) {
raport(5, "Ana");
raport(2, "Ana");
raport(6, "Ana");
return 0;
}
Rezultat
Vineri: trimite raportul săptămânal
Zi lucrătoare (5)
Zi lucrătoare (2)
Weekend (6)
Exemplul 2: noreturn și verificarea cu __has_c_attribute
opreste apelează exit și nu se mai întoarce; [[noreturn]] îi spune asta compilatorului. Aici funcția nu este apelată, ca programul să se termine normal. __has_c_attribute dă o valoare nenulă (data standardului) dacă atributul este cunoscut.
#include <stdio.h>
#include <stdlib.h>
[[noreturn]] static void opreste(const char *motiv) {
fprintf(stderr, "Eroare: %s\n", motiv);
exit(EXIT_FAILURE);
}
int main(void) {
int stoc = 12;
if (stoc < 0) {
opreste("stoc negativ");
}
printf("Stoc: %d\n", stoc);
#if __has_c_attribute(nodiscard)
printf("nodiscard este disponibil\n");
#endif
return 0;
}
Rezultat
Stoc: 12
nodiscard este disponibil
Exemplul 3: nodiscard și deprecated în acțiune
Rezultatul lui salveaza este ignorat, iar scrie_vechi este marcată învechită. Compilatorul afișează două avertismente; cu -Werror ar fi erori.
#include <stdio.h>
[[nodiscard]] int salveaza(const char *nume) {
printf("Salvez %s\n", nume);
return 0;
}
[[deprecated("folosește salveaza()")]] void scrie_vechi(void) {}
int main(void) {
salveaza("Ana");
scrie_vechi();
return 0;
}
Mesajele compilatorului (clang -std=c23 -Wall -Wextra)
exemplu.c:11:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
11 | salveaza("Ana");
| ^~~~~~~~ ~~~~~
exemplu.c:12:5: warning: 'scrie_vechi' is deprecated: folosește salveaza() [-Wdeprecated-declarations]
12 | scrie_vechi();
| ^
exemplu.c:8:3: note: 'scrie_vechi' has been explicitly marked deprecated here
8 | [[deprecated("folosește salveaza()")]] void scrie_vechi(void) {}
| ^
2 warnings generated.
Greșeli frecvente
- Pui
[[fallthrough]]fără punct și virgulă sau în alt loc decât chiar înaintea următoruluicase. Este o instrucțiune:[[fallthrough]];, ultima înainte de eticheta următoare. - Folosești
[[maybe_unused]]ca să ascunzi orice avertisment. Avertismentul despre o variabilă nefolosită indică des o greșeală reală; pune atributul doar când lipsa folosirii este intenționată. - Scrii
_Noreturnîn cod nou. Funcționează încă, dar în C23 este marcat ca învechit în favoarea lui[[noreturn]].
Comenzi înrudite
switch: Alege una din mai multe ramuri după valoarea unui întreg, cu etichete case; fără break, execuția continuă în ramura următoare.Funcții și prototipuri: Cum definești și declari funcții în C: tipul rezultatului, parametrii, prototipul și transmiterea argumentelor prin valoare.exit, atexit și EXIT_SUCCESS: Oprește programul din orice funcție, cu un cod de ieșire; atexit înregistrează funcții de rulat la final.#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.Compilarea cu gcc și clang: Cum transformi codul C într-un program executabil cu gcc sau clang și ce fac opțiunile folosite cel mai des.
Întrebări & Exemple de Cod:
Atribute [[…]]Ai o nelămurire despre utilizarea comenzii
Atribute [[…]]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.