TIMELINE DEGLI STANDARD C
AnnoStandardNome UfficialeNote
1978K&R CDefinito dal libro Kernighan & Ritchie, nessuno standard formale
1989C89ANSI X3.159-1989Primo standard ANSI — aggiunge prototipi, void, const, enum
1990C90ISO/IEC 9899:1990Identico a C89, adottato ISO
1995C95 (NA1)ISO/IEC 9899/AMD1:1995Amendment 1 — digraph, wchar.h, iso646.h
1999C99ISO/IEC 9899:1999Major: long long, VLA, // commenti, _Bool, restrict
2011C11ISO/IEC 9899:2011Atomics, threads, _Generic, _Static_assert, _Alignas
2018C17ISO/IEC 9899:2018Bug-fix release — nessuna feature nuova, solo chiarimenti
2024C23ISO/IEC 9899:2024Major: typeof, constexpr, nullptr, attributi, _BitInt
FLAG COMPILATORE PER STANDARD
GCC / Clang
FlagStandardEstensioni GNU
-std=c89 / -std=c90C89/C90No
-std=gnu89C89/C90
-std=c99C99No
-std=gnu99C99
-std=c11C11No
-std=gnu11C11
-std=c17 / -std=c18C17No
-std=gnu17C17
-std=c23 / -std=c2xC23No
-std=gnu23C23
Il default di GCC ≥ 14 è -std=gnu23. Versioni precedenti usano -std=gnu17 (GCC 11-13) o -std=gnu11 (GCC 5-10).
MSVC
FlagStandard
/std:c11C11
/std:c17C17 (default da VS 2022)
/std:clatestUltima 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__
StandardValore
C89/C90non definito (solo __STDC__ = 1)
C95 (NA1)199409L
C99199901L
C11201112L
C17201710L
C23202311L
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
FeatureDescrizione
Prototipi funzioneDichiarazioni con tipi dei parametri
voidTipo vuoto per funzioni e puntatori generici
constQualificatore di sola lettura
volatileImpedisce ottimizzazioni su variabili hardware/signal
enumEnumerazioni nominate
signedKeyword esplicita per tipi con segno
struct assignmentAssegnamento diretto fra struct (non in K&R originale)
Stringhe adiacenti"hello " "world" → concatenazione automatica
#if defined()Test condizionale per macro definite
#elifAlternativa condizionale nel preprocessore
#pragmaDirettive implementation-defined
TrigraphSequenze ??=, ??/, ecc. per tastiere senza #, \
Incompatibilità K&R → C89
Costrutto K&RStato in C89
Funzioni senza tipo di ritorno (implicito int)Permesso ma deprecato
Definizioni parametri vecchio stilePermesso ma sconsigliato
unsigned char non standardStandardizzato
C89 → C99 — TIPI & DICHIARAZIONI
Nuovi Tipi di Dato
TipoDescrizione
long long intIntero ≥ 64 bit
_BoolTipo booleano (0 o 1), con header <stdbool.h>
_ComplexNumeri complessi: float _Complex, double _Complex
_ImaginaryParte 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)
MacroDescrizione
__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
HeaderDescrizione
<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
FunzioneHeaderDescrizione
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 OrderDescrizione
memory_order_relaxedNessun ordinamento — solo atomicità
memory_order_acquireLetture successive non riordinate prima
memory_order_releaseScritture precedenti non riordinate dopo
memory_order_acq_relAcquire + Release
memory_order_seq_cstOrdine 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 / FunzioneDescrizione
thrd_create, thrd_joinCreazione e join di thread
mtx_t, mtx_lock, mtx_unlockMutex
cnd_t, cnd_wait, cnd_signalCondition variable
tss_t, tss_createThread-specific storage
call_onceInizializzazione one-time thread-safe
_Thread_localStorage 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
FeatureDescrizione
gets rimossaRimossa dallo standard (era in C89/C99) — sostituita da gets_s (Annex K)
Annex KFunzioni "sicure" (_s suffix): strcpy_s, printf_s, ecc. (opzionale)
quick_exitTerminazione rapida senza pulizia completa
timespec_getTempo ad alta risoluzione
CMPLX macroCostruzione sicura numeri complessi
Exclusive mode fileFlag "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
AreaChiarimento
__STDC_VERSION__Valore aggiornato a 201710L
Specifiche opzionaliChiarito lo stato di Annex K (bounds-checking) e Annex L (analyzability)
Definizione di aligned_allocChiarito il requisito che size sia multiplo di alignment
Atomic initChiarita l'inizializzazione di oggetti atomici
Tipo di u'x'Chiarito che char16_t e char32_t sono tipi distinti
Sottogruppi opzionaliLista formale di feature opzionali con macro di test
Feature Test Macro (Opzionali)
MacroSignificato 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
AttributoDescrizione
[[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 / FunzioneDescrizione
<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_explicitCome memset ma non ottimizzabile via (per sicurezza)
strdup, strndupFinalmente nello standard (erano POSIX)
memalignmentQuery allineamento di un puntatore a runtime
free_sized, free_aligned_sizedDeallocazione con dimensione nota (ottimizzazione)
timespec_getresRisoluzione del timer
C17 → C23 — RIMOZIONI & DEPRECAZIONI
Rimossi in C23
FeatureAlternativa
TrigraphRimossi 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
CambiamentoDettaglio
autoDa storage class specifier a type inference (con inizializzatore)
Funzioni senza parametriint f() ora equivale a int f(void) (non più "parametri sconosciuti")
Rappresentazione interiC23 richiede complemento a 2 (prima era implementation-defined)
Unsigned in <limits.h>I tipi unsigned usano modulo 2N (sempre vero in pratica, ora standard)
Unreachableunreachable() 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
FeatureC89C99C11C17C23
Prototipi funzione
// commenti
long long
Dichiarazioni miste
VLAopz.opz.opz.
restrict
Designated init
Compound literals
inline
_Generic
_Static_assert
_Atomicopz.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)
StandardGCCClangMSVC
C89/C90CompletoCompletoCompleto
C99Completo (4.5+)CompletoParziale
C11Completo (4.9+)Completo (3.6+)Parziale (VS 2019+)
C17Completo (8+)Completo (6+)Completo (VS 2019 16.8+)
C23In corso (14+)In corso (18+)Parziale
GUIDA ALLA MIGRAZIONE
C89 → C99: Azioni Consigliate
AzioneDettaglio
Aggiungere -std=c99Abilitare 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'usoSpostare dichiarazioni vicino al primo utilizzo
Usare snprintfSostituire sprintf con la versione sicura
C99 → C11: Azioni Consigliate
AzioneDettaglio
Aggiungere -std=c11Quasi completamente retrocompatibile
Usare _Static_assertValidare assunzioni a compile-time
Struct/union anonimiSemplificare accesso a campi innestati
Valutare _GenericPer macro type-safe al posto di cast manuali
Verificare VLASe usati, testare con __STDC_NO_VLA__ per portabilità
C11/C17 → C23: Azioni Consigliate
AzioneDettaglio
Aggiungere -std=c23Verificare la compatibilità del compilatore
Eliminare definizioni K&RObbligatorio — non compilano più
Rimuovere <stdbool.h>bool è keyword nativa
Usare [[noreturn]]Sostituire _Noreturn / <stdnoreturn.h>
Usare nullptrPiù sicuro di NULL / 0 per puntatori
Valutare typeofMacro type-safe senza estensioni GNU
Usare constexprPer costanti al posto di #define dove possibile
Valutare #embedInclusione 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.