◈ TIMELINE DEGLI STANDARD C
| Anno | Standard | Nome Ufficiale | Note |
|---|---|---|---|
| 1978 | K&R C | — | Definito dal libro Kernighan & Ritchie, nessuno standard formale |
| 1989 | C89 | ANSI X3.159-1989 | Primo standard ANSI — aggiunge prototipi, void, const, enum |
| 1990 | C90 | ISO/IEC 9899:1990 | Identico a C89, adottato ISO |
| 1995 | C95 (NA1) | ISO/IEC 9899/AMD1:1995 | Amendment 1 — digraph, wchar.h, iso646.h |
| 1999 | C99 | ISO/IEC 9899:1999 | Major: long long, VLA, // commenti, _Bool, restrict |
| 2011 | C11 | ISO/IEC 9899:2011 | Atomics, threads, _Generic, _Static_assert, _Alignas |
| 2018 | C17 | ISO/IEC 9899:2018 | Bug-fix release — nessuna feature nuova, solo chiarimenti |
| 2024 | C23 | ISO/IEC 9899:2024 | Major: typeof, constexpr, nullptr, attributi, _BitInt |
◈ FLAG COMPILATORE PER STANDARD
GCC / Clang
| Flag | Standard | Estensioni GNU |
|---|---|---|
-std=c89 / -std=c90 | C89/C90 | No |
-std=gnu89 | C89/C90 | Sì |
-std=c99 | C99 | No |
-std=gnu99 | C99 | Sì |
-std=c11 | C11 | No |
-std=gnu11 | C11 | Sì |
-std=c17 / -std=c18 | C17 | No |
-std=gnu17 | C17 | Sì |
-std=c23 / -std=c2x | C23 | No |
-std=gnu23 | C23 | Sì |
Il default di GCC ≥ 14 è
-std=gnu23. Versioni precedenti usano -std=gnu17 (GCC 11-13) o -std=gnu11 (GCC 5-10).MSVC
| Flag | Standard |
|---|---|
/std:c11 | C11 |
/std:c17 | C17 (default da VS 2022) |
/std:clatest | Ultima versione supportata |
MSVC non ha mai supportato pienamente C99; il supporto parte da C11/C17.
◈ RILEVARE LO STANDARD A COMPILE-TIME
/* La macro __STDC_VERSION__ identifica lo standard */ #if __STDC_VERSION__ >= 202311L /* C23 */ #elif __STDC_VERSION__ >= 201710L /* C17 */ #elif __STDC_VERSION__ >= 201112L /* C11 */ #elif __STDC_VERSION__ >= 199901L /* C99 */ #elif defined(__STDC__) /* C89/C90 (__STDC_VERSION__ non esisteva ancora) */ #else /* Pre-standard / K&R */ #endif
Valori di __STDC_VERSION__
| Standard | Valore |
|---|---|
| C89/C90 | non definito (solo __STDC__ = 1) |
| C95 (NA1) | 199409L |
| C99 | 199901L |
| C11 | 201112L |
| C17 | 201710L |
| C23 | 202311L |
◈ K&R C → C89/C90 (ANSI C)
Prototipi di Funzione
/* K&R — nessun tipo nei parametri */ int somma(a, b) int a; int b; { return a + b; } /* C89 — prototipi ANSI */ int somma(int a, int b) { return a + b; }
In K&R il compilatore non verificava il numero e tipo degli argomenti. I prototipi C89 eliminano questa classe di bug.
Novità Principali di C89
| Feature | Descrizione |
|---|---|
| Prototipi funzione | Dichiarazioni con tipi dei parametri |
void | Tipo vuoto per funzioni e puntatori generici |
const | Qualificatore di sola lettura |
volatile | Impedisce ottimizzazioni su variabili hardware/signal |
enum | Enumerazioni nominate |
signed | Keyword esplicita per tipi con segno |
struct assignment | Assegnamento diretto fra struct (non in K&R originale) |
| Stringhe adiacenti | "hello " "world" → concatenazione automatica |
#if defined() | Test condizionale per macro definite |
#elif | Alternativa condizionale nel preprocessore |
#pragma | Direttive implementation-defined |
| Trigraph | Sequenze ??=, ??/, ecc. per tastiere senza #, \ |
Incompatibilità K&R → C89
| Costrutto K&R | Stato in C89 |
|---|---|
Funzioni senza tipo di ritorno (implicito int) | Permesso ma deprecato |
| Definizioni parametri vecchio stile | Permesso ma sconsigliato |
unsigned char non standard | Standardizzato |
◈ C89 → C99 — TIPI & DICHIARAZIONI
Nuovi Tipi di Dato
| Tipo | Descrizione |
|---|---|
long long int | Intero ≥ 64 bit |
_Bool | Tipo booleano (0 o 1), con header <stdbool.h> |
_Complex | Numeri complessi: float _Complex, double _Complex |
_Imaginary | Parte immaginaria pura (opzionale) |
Dichiarazioni Miste
/* C89 — dichiarazioni solo in cima al blocco */ void f(void) { int x = 10; int y = 20; printf("%d\n", x + y); } /* C99 — dichiarazioni ovunque nel blocco */ void f(void) { printf("inizio\n"); int x = 10; // dichiarazione dopo statement int y = 20; printf("%d\n", x + y); }
Variabile nel for
/* C89 */ int i; for (i = 0; i < 10; i++) { ... } /* C99 — dichiarazione nel for */ for (int i = 0; i < 10; i++) { ... }
VLA — Variable-Length Array
void f(int n) { int arr[n]; // C99: dimensione determinata a runtime // Allocato sullo stack — attenzione a n grandi! }
I VLA sono stati resi opzionali in C11 (feature test:
__STDC_NO_VLA__). In C23 il tipo VLA rimane, ma gli oggetti VLA con allocazione automatica sono opzionali.restrict
/* Il compilatore può assumere che p e q non si sovrappongono */ void copia(int *restrict dest, const int *restrict src, size_t n) { for (size_t i = 0; i < n; i++) dest[i] = src[i]; }
Header a Larghezza Fissa
#include <stdint.h> // int8_t, int16_t, int32_t, int64_t #include <inttypes.h> // macro di formato: PRId32, PRIx64, ecc. int32_t x = 42; uint64_t y = 0xDEADBEEF; printf("x = %" PRId32 "\n", x);
◈ C89 → C99 — SINTASSI & COSTRUTTI
Commenti // in Linea
/* C89 — solo commenti blocco */ int x = 42; /* commento */ // C99 — commenti stile C++ int x = 42; // commento in linea
Designated Initializers
/* C89 — ordine posizionale obbligatorio */ int arr[5] = {0, 0, 0, 7, 0}; /* C99 — designated initializers */ int arr[5] = { [3] = 7 }; struct Point p = { .x = 10, .y = 20 };
Compound Literals
/* Crea un oggetto temporaneo senza nome */ draw_point( (struct Point){.x = 3, .y = 4} ); /* Array temporaneo */ int *p = (int[]){1, 2, 3};
Inline Functions
/* C99: suggerimento al compilatore per inlining */ static inline int max(int a, int b) { return (a > b) ? a : b; }
La semantica di
inline in C99 differisce da C++: senza static, serve una definizione esterna in un'altra unità di traduzione.Flexible Array Member
struct Buffer { size_t len; char data[]; // C99: membro flessibile (ultimo campo) }; struct Buffer *b = malloc(sizeof(struct Buffer) + 1024); b->len = 1024;
◈ C89 → C99 — PREPROCESSORE
Macro Variadic
/* C99: macro con numero variabile di argomenti */ #define LOG(fmt, ...) \ fprintf(stderr, "[LOG] " fmt "\n", __VA_ARGS__) LOG("valore: %d", 42);
_Pragma
/* C89: #pragma non utilizzabile dentro macro */ /* C99: _Pragma come operatore */ #define PACK_BEGIN _Pragma("pack(push,1)") #define PACK_END _Pragma("pack(pop)")
Nuove Macro Predefinite (C99)
| Macro | Descrizione |
|---|---|
__func__ | Nome della funzione corrente (come stringa) |
__STDC_VERSION__ | Versione dello standard (199901L) |
__STDC_HOSTED__ | 1 se implementazione hosted, 0 se freestanding |
◈ C89 → C99 — LIBRERIA STANDARD
Nuovi Header C99
| Header | Descrizione |
|---|---|
<stdbool.h> | Macro bool, true, false |
<stdint.h> | Tipi interi a larghezza fissa: int8_t, int32_t, ecc. |
<inttypes.h> | Macro di formato per printf/scanf su tipi fissi |
<complex.h> | Aritmetica complessa: cabs, carg, cimag, creal |
<tgmath.h> | Macro type-generic per funzioni matematiche |
<fenv.h> | Controllo ambiente floating-point (rounding, eccezioni) |
Funzioni Aggiunte
| Funzione | Header | Descrizione |
|---|---|---|
snprintf | <stdio.h> | Printf con limite di buffer (sicura) |
va_copy | <stdarg.h> | Copia una va_list |
llabs, lldiv | <stdlib.h> | Operazioni su long long |
round, trunc, remainder | <math.h> | Arrotondamento floating-point |
isnan, isinf, isfinite | <math.h> | Classificazione valori speciali |
◈ C99 → C11 — ATOMICS & THREADS
Operazioni Atomiche
#include <stdatomic.h> _Atomic int counter = 0; /* Oppure con la macro */ atomic_int counter = ATOMIC_VAR_INIT(0); atomic_store(&counter, 42); int val = atomic_load(&counter); atomic_fetch_add(&counter, 1);
| Memory Order | Descrizione |
|---|---|
memory_order_relaxed | Nessun ordinamento — solo atomicità |
memory_order_acquire | Letture successive non riordinate prima |
memory_order_release | Scritture precedenti non riordinate dopo |
memory_order_acq_rel | Acquire + Release |
memory_order_seq_cst | Ordine totale (default) |
Feature opzionale: verificare con
__STDC_NO_ATOMICS__.Thread C11
#include <threads.h> int worker(void *arg) { printf("Thread %d\n", *(int*)arg); return 0; } int main(void) { thrd_t t; int id = 1; thrd_create(&t, worker, &id); thrd_join(t, NULL); }
| Tipo / Funzione | Descrizione |
|---|---|
thrd_create, thrd_join | Creazione e join di thread |
mtx_t, mtx_lock, mtx_unlock | Mutex |
cnd_t, cnd_wait, cnd_signal | Condition variable |
tss_t, tss_create | Thread-specific storage |
call_once | Inizializzazione one-time thread-safe |
_Thread_local | Storage duration thread-local |
Feature opzionale: verificare con
__STDC_NO_THREADS__. In pratica, molti usano POSIX Threads (pthread) per compatibilità.◈ C99 → C11 — _Generic & _Static_assert
_Generic — Selezione Type-Based
#define type_name(x) _Generic((x), \ int: "int", \ float: "float", \ double: "double", \ char*: "char*", \ default: "altro") printf("%s\n", type_name(42)); // "int" printf("%s\n", type_name(3.14)); // "double"
/* Esempio pratico: abs() type-generic */ #define generic_abs(x) _Generic((x), \ int: abs, \ long: labs, \ float: fabsf, \ double: fabs)(x)
_Static_assert — Asserzioni a Compile-Time
/* C11 — richiede messaggio stringa */ _Static_assert(sizeof(int) >= 4, "int deve essere almeno 32 bit"); /* C23 — messaggio opzionale */ static_assert(sizeof(int) >= 4);
_Noreturn
#include <stdnoreturn.h> // macro noreturn -> _Noreturn _Noreturn void fatal(const char *msg) { fprintf(stderr, "FATAL: %s\n", msg); abort(); }
In C23,
_Noreturn e <stdnoreturn.h> sono deprecati a favore dell'attributo [[noreturn]].◈ C99 → C11 — ALLINEAMENTO
#include <stdalign.h> // macro alignas -> _Alignas, alignof -> _Alignof /* Forzare allineamento */ _Alignas(16) float vec[4]; // allineato a 16 byte _Alignas(double) char buf[128]; // allineato come double /* Query allineamento */ size_t a = _Alignof(double); // tipicamente 8 size_t b = _Alignof(max_align_t); // allineamento massimo standard
aligned_alloc
/* Allocazione dinamica allineata (C11) */ void *p = aligned_alloc(64, 256); // 256 byte allineati a 64 /* size deve essere multiplo di alignment */ free(p);
◈ C99 → C11 — UNICODE & VARIE
Caratteri Unicode
#include <uchar.h> char16_t c16 = u'A'; // UTF-16 char32_t c32 = U'A'; // UTF-32 const char16_t *s16 = u"ciao"; const char32_t *s32 = U"ciao";
Strutture e Union Anonime
struct Registro { int tipo; union { // C11: union anonima int i_val; float f_val; char *s_val; }; // accesso diretto: r.i_val };
Altre Novità C11
| Feature | Descrizione |
|---|---|
gets rimossa | Rimossa dallo standard (era in C89/C99) — sostituita da gets_s (Annex K) |
| Annex K | Funzioni "sicure" (_s suffix): strcpy_s, printf_s, ecc. (opzionale) |
quick_exit | Terminazione rapida senza pulizia completa |
timespec_get | Tempo ad alta risoluzione |
CMPLX macro | Costruzione sicura numeri complessi |
| Exclusive mode file | Flag "x" in fopen — fallisce se file esiste |
◈ C11 → C17 — BUG-FIX RELEASE
C17 (ISO/IEC 9899:2018) non introduce feature nuove. È un Defect Report release che corregge ambiguità e difetti nella specifica C11.
Chiarimenti Principali
| Area | Chiarimento |
|---|---|
__STDC_VERSION__ | Valore aggiornato a 201710L |
| Specifiche opzionali | Chiarito lo stato di Annex K (bounds-checking) e Annex L (analyzability) |
Definizione di aligned_alloc | Chiarito il requisito che size sia multiplo di alignment |
| Atomic init | Chiarita l'inizializzazione di oggetti atomici |
Tipo di u'x' | Chiarito che char16_t e char32_t sono tipi distinti |
| Sottogruppi opzionali | Lista formale di feature opzionali con macro di test |
Feature Test Macro (Opzionali)
| Macro | Significato se definita |
|---|---|
__STDC_NO_ATOMICS__ | Atomics non supportate |
__STDC_NO_COMPLEX__ | Numeri complessi non supportati |
__STDC_NO_THREADS__ | Threads C11 non supportati |
__STDC_NO_VLA__ | VLA non supportati |
__STDC_LIB_EXT1__ | Annex K (bounds-checking) disponibile |
__STDC_ANALYZABLE__ | Annex L (analyzability) disponibile |
Per la maggior parte del codice, compilare con
-std=c17 vs -std=c11 non produce differenze osservabili. Il passaggio è sempre retrocompatibile.◈ C17 → C23 — TIPI & ATTRIBUTI
typeof
/* C23: typeof come keyword (era estensione GNU) */ int x = 42; typeof(x) y = x; // y è int /* typeof_unqual — rimuove qualificatori */ const int c = 10; typeof_unqual(c) m = c; // m è int (non const int)
nullptr e nullptr_t
#include <stddef.h> /* C89-C17: NULL è tipicamente (void*)0 o 0 */ int *p = NULL; /* C23: nullptr è un vero null pointer constant */ int *q = nullptr; /* nullptr_t è il tipo di nullptr */ nullptr_t n = nullptr;
nullptr non è convertibile a int (a differenza di 0 / NULL), eliminando bug comuni._BitInt — Interi a Larghezza Arbitraria
/* C23: interi con esattamente N bit */ _BitInt(128) big = 0; unsigned _BitInt(256) huge = 0; /* Utile per crittografia, hashing, ecc. */
bool, true, false come Keyword
/* C99-C17: bool è macro in <stdbool.h> */ #include <stdbool.h> bool flag = true; /* C23: bool, true, false sono keyword native */ bool flag = true; // nessun #include necessario
Attributi Standard
/* C23: sintassi attributi [[...]] (come C++) */ [[noreturn]] void fatal(const char *msg); [[deprecated("usa nuova_api()")]] void vecchia_api(void); [[maybe_unused]] int debug_var; [[nodiscard]] int alloca_risorsa(void); [[fallthrough]]; // in un case senza break
| Attributo | Descrizione |
|---|---|
[[noreturn]] | La funzione non ritorna mai (sostituisce _Noreturn) |
[[deprecated]] | Genera warning se usato |
[[maybe_unused]] | Sopprime warning per entità non usate |
[[nodiscard]] | Warning se il valore di ritorno è ignorato |
[[fallthrough]] | Fall-through intenzionale in switch |
[[unsequenced]] | La funzione non ha side-effect osservabili |
[[reproducible]] | Chiamate ripetute con stessi arg danno stesso risultato |
◈ C17 → C23 — SINTASSI & COSTANTI
constexpr
/* C23: oggetti constexpr — valutazione a compile-time */ constexpr int MAX = 100; constexpr double PI = 3.14159265358979; /* Utilizzabile dove serve un'espressione costante */ int arr[MAX]; /* NB: solo per oggetti, NON per funzioni (a differenza di C++) */
Letterali Binari e Separatore Cifre
/* C23: prefisso 0b / 0B per binario */ int mask = 0b11001010; /* C23: separatore ' per leggibilità */ long pop = 60'000'000; int hex = 0xFF'A0'00; int bin = 0b1111'0000'1010'0101;
Label senza Statement e Dichiarazioni dopo Label
/* C89-C17: un label deve precedere uno statement */ end: ; // serviva uno statement vuoto /* C23: label può precedere dichiarazioni o stare a fine blocco */ end: int result = 0; // OK in C23 }
Inizializzazione Vuota
/* C23: {} inizializza a zero qualsiasi tipo */ int x = {}; struct Point p = {}; // equivalente a {0} ma più chiaro int arr[10] = {}; // tutto zero
auto Type Inference
/* C23: auto con inizializzatore deduce il tipo */ auto x = 42; // int auto pi = 3.14; // double auto p = malloc(64); // void* /* NB: non come C++ auto — solo per variabili con inizializzatore */
In C89-C17,
auto era uno storage class specifier (raramente usato). C23 gli dà un nuovo significato di type inference.Stringhe UTF-8
/* C23: prefisso u8 per stringhe e char UTF-8 */ const char *s = u8"Ciao mondo"; // char[] con encoding UTF-8 unsigned char c = u8'A'; // char8_t in pratica
◈ C17 → C23 — PREPROCESSORE & LIBRERIA
Nuove Direttive Preprocessore
/* #elifdef / #elifndef — combinano #elif + defined */ #ifdef LINUX /* codice Linux */ #elifdef WINDOWS /* codice Windows */ #elifndef EMBEDDED /* codice non embedded */ #endif /* #warning — emette un warning (era estensione, ora standard) */ #warning "Questa feature è sperimentale" /* #embed — include dati binari come array */ const unsigned char icon[] = { #embed "icon.png" };
__VA_OPT__ — Macro Variadic Migliorate
/* Problema C99: virgola in eccesso senza argomenti variadic */ #define LOG_OLD(fmt, ...) printf(fmt, __VA_ARGS__) LOG_OLD("test"); // errore: printf("test", ) ← virgola extra /* C23: __VA_OPT__ gestisce il caso zero-argomenti */ #define LOG(fmt, ...) printf(fmt __VA_OPT__(,) __VA_ARGS__) LOG("test"); // OK: printf("test") LOG("%d", 42); // OK: printf("%d", 42)
Nuovi Header e Funzioni C23
| Header / Funzione | Descrizione |
|---|---|
<stdbit.h> | Operazioni bit: stdc_leading_zeros, stdc_count_ones, stdc_bit_width |
<stdckdint.h> | Aritmetica checked: ckd_add, ckd_sub, ckd_mul (overflow detection) |
memset_explicit | Come memset ma non ottimizzabile via (per sicurezza) |
strdup, strndup | Finalmente nello standard (erano POSIX) |
memalignment | Query allineamento di un puntatore a runtime |
free_sized, free_aligned_sized | Deallocazione con dimensione nota (ottimizzazione) |
timespec_getres | Risoluzione del timer |
◈ C17 → C23 — RIMOZIONI & DEPRECAZIONI
Rimossi in C23
| Feature | Alternativa |
|---|---|
| Trigraph | Rimossi completamente (erano già poco usati) |
| Definizioni K&R (old-style) | Usare prototipi ANSI |
_Noreturn keyword | [[noreturn]] attributo |
<stdnoreturn.h> | [[noreturn]] |
<stdalign.h> | alignas / alignof sono keyword native |
<stdbool.h> | bool, true, false sono keyword native |
Cambiamenti Semantici
| Cambiamento | Dettaglio |
|---|---|
auto | Da storage class specifier a type inference (con inizializzatore) |
| Funzioni senza parametri | int f() ora equivale a int f(void) (non più "parametri sconosciuti") |
| Rappresentazione interi | C23 richiede complemento a 2 (prima era implementation-defined) |
Unsigned in <limits.h> | I tipi unsigned usano modulo 2N (sempre vero in pratica, ora standard) |
| Unreachable | unreachable() macro in <stddef.h> per codice irraggiungibile |
Il cambiamento più impattante è la rimozione delle definizioni K&R: codice molto vecchio con
int f(a, b) int a; int b; {...} non compila più in -std=c23.◈ TABELLA COMPATIBILITÀ FEATURE
Feature per Standard
| Feature | C89 | C99 | C11 | C17 | C23 |
|---|---|---|---|---|---|
| Prototipi funzione | ✓ | ✓ | ✓ | ✓ | ✓ |
// commenti | ✗ | ✓ | ✓ | ✓ | ✓ |
long long | ✗ | ✓ | ✓ | ✓ | ✓ |
| Dichiarazioni miste | ✗ | ✓ | ✓ | ✓ | ✓ |
| VLA | ✗ | ✓ | opz. | opz. | opz. |
restrict | ✗ | ✓ | ✓ | ✓ | ✓ |
| Designated init | ✗ | ✓ | ✓ | ✓ | ✓ |
| Compound literals | ✗ | ✓ | ✓ | ✓ | ✓ |
inline | ✗ | ✓ | ✓ | ✓ | ✓ |
_Generic | ✗ | ✗ | ✓ | ✓ | ✓ |
_Static_assert | ✗ | ✗ | ✓ | ✓ | ✓ |
_Atomic | ✗ | ✗ | opz. | opz. | opz. |
<threads.h> | ✗ | ✗ | opz. | opz. | opz. |
| Struct/union anonimi | ✗ | ✗ | ✓ | ✓ | ✓ |
_Alignas / _Alignof | ✗ | ✗ | ✓ | ✓ | ✓ |
typeof | ✗ | ✗ | ✗ | ✗ | ✓ |
nullptr | ✗ | ✗ | ✗ | ✗ | ✓ |
constexpr | ✗ | ✗ | ✗ | ✗ | ✓ |
_BitInt | ✗ | ✗ | ✗ | ✗ | ✓ |
Attributi [[...]] | ✗ | ✗ | ✗ | ✗ | ✓ |
#embed | ✗ | ✗ | ✗ | ✗ | ✓ |
Letterali binari 0b | ✗ | ✗ | ✗ | ✗ | ✓ |
bool keyword | ✗ | ✗ | ✗ | ✗ | ✓ |
| Trigraph | ✓ | ✓ | ✓ | ✓ | ✗ |
| K&R definitions | ✓ | ✓ | ✓ | ✓ | ✗ |
Supporto Compilatori (indicativo)
| Standard | GCC | Clang | MSVC |
|---|---|---|---|
| C89/C90 | Completo | Completo | Completo |
| C99 | Completo (4.5+) | Completo | Parziale |
| C11 | Completo (4.9+) | Completo (3.6+) | Parziale (VS 2019+) |
| C17 | Completo (8+) | Completo (6+) | Completo (VS 2019 16.8+) |
| C23 | In corso (14+) | In corso (18+) | Parziale |
◈ GUIDA ALLA MIGRAZIONE
C89 → C99: Azioni Consigliate
| Azione | Dettaglio |
|---|---|
Aggiungere -std=c99 | Abilitare lo standard e verificare warning |
Sostituire /* */ con // | Dove appropriato per commenti in linea |
Usare <stdint.h> | Sostituire tipi platform-specific con int32_t, ecc. |
Usare <stdbool.h> | Sostituire int flag con bool |
| Dichiarazioni al punto d'uso | Spostare dichiarazioni vicino al primo utilizzo |
Usare snprintf | Sostituire sprintf con la versione sicura |
C99 → C11: Azioni Consigliate
| Azione | Dettaglio |
|---|---|
Aggiungere -std=c11 | Quasi completamente retrocompatibile |
Usare _Static_assert | Validare assunzioni a compile-time |
| Struct/union anonimi | Semplificare accesso a campi innestati |
Valutare _Generic | Per macro type-safe al posto di cast manuali |
| Verificare VLA | Se usati, testare con __STDC_NO_VLA__ per portabilità |
C11/C17 → C23: Azioni Consigliate
| Azione | Dettaglio |
|---|---|
Aggiungere -std=c23 | Verificare la compatibilità del compilatore |
| Eliminare definizioni K&R | Obbligatorio — non compilano più |
Rimuovere <stdbool.h> | bool è keyword nativa |
Usare [[noreturn]] | Sostituire _Noreturn / <stdnoreturn.h> |
Usare nullptr | Più sicuro di NULL / 0 per puntatori |
Valutare typeof | Macro type-safe senza estensioni GNU |
Usare constexpr | Per costanti al posto di #define dove possibile |
Valutare #embed | Inclusione dati binari senza tool esterni |
Regola generale: ogni standard è largamente retrocompatibile col precedente. Le rotture più significative sono C23 (rimozione K&R, cambio semantica
auto e f()) e C11 (gets rimossa). Compilare con -Wall -Wextra -pedantic evidenzia i problemi.