Nei titoli e nei testi troverete qualche rimando cinematografico (ebbene si, sono un cinefilo). Se non vi interessano fate finta di non vederli, già che non sono fondamentali per la comprensione dei post...

Di questo blog ho mandato avanti, fino a Settembre 2018, anche una versione in Spagnolo. Potete trovarla su El arte de la programación en C. Buona lettura.

venerdì 12 dicembre 2025

Warning Peaks
perché i warning sono importanti in C - pt.1

Dale Cooper: [parlando a un registratore] Diane, quando due eventi, due fatti riguardanti la stessa indagine si verificano simultaneamente, dobbiamo sempre considerarli con la massima attenzione.

Nella bellissima (e mitica) serie TV Twin Peaks il Maestro David Lynch (insieme al fido Mark Frost) ci spiegava che nulla è come appare a prima vista, e che in una investigazione bisogna analizzare tutti i dettagli, anche i più insignificanti, per giungere alla verità. Ebbene si, questo è valido anche nella nostra amata programmazione in C: il nostro strumento principale è il compilatore, che oltre a costruire l'eseguibile dell'applicazione su cui abbiamo lavorato ci fornisce un sacco di informazioni utili sul codice che abbiamo scritto, mostrandoci errori, vulnerabilità e avvisi, i famosi warning, che sono molto (ma molto) più importanti di quello che si pensa... Come avrete già intuito, in questo articolo parleremo di warning!

...ma l'hai letto l'ultimo warning?...

Nella mia lunga carriera di programmatore ho incontrato, a volte, colleghi che non davano la dovuta attenzione ai warning di compilazione, considerandoli semplici avvisi di scarsa importanza... e questo è un errore fondamentale! Anzi, ora che ci penso, un giorno assistei a un interessante dialogo tra mio cuggino e un suo collega. Si, credo che sia ora di far intervenire (sia pur indirettamente) mio cuggino, che manca da tempo da queste pagine. Il dialogo che intercettai era, più o meno, questo:

mio cuggino: Tu sei un programmatore professionista, vero?
programmatore: Si, è il mio mestiere. Anni e anni di esperienza...
mio cuggino: Ma dimmi una cosa: quando compili che linea di compilazione usi?
programmatore: Mah, qualcosa del tipo "gcc -o programma programma.c".
mio cuggino: Ma lo sai che con quella linea vedi solo i warning di base? E così te ne sfuggono alcuni molto importanti.
programmatore: Beh, ma i warning sono solo avvertenze, non servono a niente, già vedere quelli di base mi confonde abbastanza le idee...
mio cuggino: Guarda, se vuoi sviluppare del buon codice dovresti perlomeno attivare il flag -Wall e magari anche il -Wextra...
programmatore: -Wall? -Wextra? Mai sentiti, a cosa servono?. 
mio cuggino: Mai pensato di cambiare mestiere?

Ecco, come sempre mio cuggino fu molto tranciante, ma quella volta io pensai la stessa cosa, ma non lo dissi (tanto l'aveva già detto lui, ah ah ah... si scherza, eh!).

Come dite? Sto esagerando? Ok, allora è il caso di fornire qualche piccolo esempietto... vai col codice!

// uninit.c
#include <stdio.h>

int main()
{
int index;
char *str = "salve, mondo";

printf("%c\n", str[index]);
return 0;
}

Ecco, questo è un codice semplicissimo che stampa il contenuto di una stringa. Proviamo a compilare ed eseguire questo uninit.c:

aldo@Linux $ gcc uninit.c -o uninit
aldo@Linux $ ./uninit
Errore di segmentazione (core dump creato)

Ma va! Un bel segmentation fault per un codice così semplice! E il compilatore non mi dice nulla? Proviamo a aggiunger il flag -Wall:

aldo@Linux $ gcc -Wall uninit.c -o uninit
uninit.c: In function ‘main’:
uninit.c:9:23: warning: ‘index’ is used uninitialized [-Wuninitialized]
9 | printf("%c\n", str[index]);
| ^
uninit.c:6:9: note: ‘index’ was declared here
6 | int index;
| ^~~~~

Oohh... e io che pensavo che i warning non servissero a niente (ah ah ah). Ecco, il codice mostrato è un semplice main di cinque righe, e quindi l'errore si vede facilmente, ma immaginate quando questo pezzetto di codice viene immerso in un grande progetto di centinaia di migliaia di linee: diventerà quasi invisibile, e per risolvere il problema sarà meglio dare un occhiata ai warning, no?

Ed ora un altro esempio con un warning che prima usciva solo attivando il flag -Wformat (che è incluso nel -Wall) e che ora esce anche a livello base (senza nessun flag), ma che molti non notano "perché leggere tutti i warning non serve" (ehm...) :

// format.c
#include <stdio.h>

int main()
{
int a = 12;
printf("%s\n", a);
return 0;
}

Ok, anche questo è un codice semplicissimo che stampa nel terminale una stringa. Proviamo a compilare ed eseguire questo format.c:

aldo@Linux $ gcc format.c -o format
format.c: In function ‘main’:
format.c:8:14: warning: format ‘%s’ expects argument of type ‘char *, but argument 2 has type ‘int[-Wformat=]
8 | printf("%s\n", a);
| ~^ ~
| | |
| | int
| char *
| %d
aldo@Linux $ ./format
Errore di segmentazione (core dump creato)

Ma va! Un altro bel segmentation fault per un codice così semplice! E il compilatore me lo dice già di base! Certo che se non dò peso al warning (magari perché ce ne sono così tanti che faccio finta di non vederli...) il problema verrà poi quando eseguo l'applicazione. Male, male, molto male...

E non parliamo dei problemi che non appaiono costantemente a run-time, perché dipendono, sfortunatamente, da come è occupata la memoria al momento dell'esecuzione (quindi, a volte appaiono e a volte no): costerà moltissimo risolvere questi errori, quando invece sarebbe stato sufficiente risolvere tutti i warning di compilazione man mano che si presentavano! Spero di essere stato chiaro: i warning sono importanti, e non solo quelli di base!

Ok, per oggi può bastare. Nella seconda parte dell'articolo vedremo una panoramica dei flag di compilazione consigliati per realizzare una applicazione a prova di bomba. Come sempre vi raccomando di non trattenere il respiro nell'attesa (può nuocere gravemente alla salute...).

Ciao, e al prossimo post!