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.

sabato 7 maggio 2016

Strerror Simple
come scrivere una pseudo-strerror in C

Questo è un post facile. Magari un po' più del Blood dell'esordio dei grandi Coen brothers (uhm... il sangue non è mai facile). Si, un post facile facile, ma più utile di quel che sembra, tanto per dimostrare che a problema semplice soluzione semplice: se per fare una scemata avete scritto 1000000 di incomprensibili righe di codice avete sbagliato qualcosa: meglio cancellare e ricominciare, sicuramente vi verrà meglio.
...e questo tu lo chiami semplice? SEMPLICE???
Allora, supponiamo di avere dei codici che rappresentano qualcosa (errori, tipi di messaggi, warning di sistema, ciabatte, formaggi... qualsiasi cosa), e volete, per esempio, mostrarli in un bel sistema di log (magari come quello visto qui, qui e qui), ma non come numeri (ehi, siamo esseri umani, mica Sheldon Cooper): siamo abituati a visualizzare cose, non numeri. Vogliamo vedere le stringhe mnemoniche corrispondenti ai numeri.
...e da oggi vi parlerò usando solo codice binario...
Ecco, scrivere il codice per una cosa del genere è veramente molto semplice... vai col codice!
#include<stdio.h>

// codici stringhe
#define CODE_SPIDERMAN  0
#define CODE_THOR       1
#define CODE_DAREDEVIL  2
#define CODE_PUNISHER   3

// array stringhe
static const char* const strings[] = {
    "Spiderman",
    "Thor",
    "Daredevil",
    "Punisher"
};

// ottieni una stringa
const char* getString(
    int code)
{
    // calcola size
    int size = sizeof(strings) / sizeof(char*);

    // test se il codice va in overflow
    if (code >= 0 && code < size)
        return(strings[code]);
    else
        return("errore: codice non valido");
}

// main() per test
void main()
{
    // loop di input
    for (;;) {
        // chiede il codice
        int code;
        printf("get stringa numero? ");
        scanf("%d", &code);

        // mostra la stringa corrispondente al codice
        printf("stringa = %s\n", getString(code));
    }
}
Allora, tanto per non ripetermi: il codice qui sopra è, evidentemente, auto-esplicativo, ampiamente commentato e con commenti che parlano da soli.

Come avrete notato è sufficiente (almeno in una implementazione base) definire i codici e scrivere le stringe corrispondenti (nello stesso ordine!) in un array. Poi si scrive la funzione per estrarle che esegue, semplicemente, un return di array[codice]. Ho aggiunto un minimo (indispensabile) di controlli, per evitare l'uso di codici negativi o non esistenti (overflow). Notare che il size è calcolato dinamicamente, quindi possiamo aggiungere, col tempo, codici (e stringhe) senza bisogno di modificare la getString() (molto bene!). Ovviamente il codice presentato (che include anche un semplice main() di test interattivo) si può complicare e sofisticare quanto si vuole, ma rispettando l'idea base, che è semplice.

In un progetto reale il file qui sopra bisogna spezzarlo in tre: i codici (e un prototipo) andranno in un header-file che verrà incluso da tutti i source-file della applicazione che necessitano usare la getString(). La getString() e l'array (statico) di stringhe andranno in un source-file apposito (che chiameremo getstring.c) che verrà compilato e linkato insieme agli altri file del progetto.

Perché nel titolo ho citato la strerror()? Perché la nostra getString() fa, più o meno, lo stesso lavoro della strerror() di sistema, ossia restituisce la stringa corrispondente al codice di errore errno. Ovviamente la strerror() è un po' piu sofisticata: usa un buffer statico interno su cui esegue strcpy() e altre cosette... tra l'altro proprio per colpa del buffer interno non è thread safe, e, in alcuni casi ci costringe a usare la strerror_r(): ma questa è un altra storia, e questo è un post semplice, non divaghiamo.

Certo, se poi qualcuno di mestiere fa il complicatore di cose facili (che, sfortunatamente, è un lavoro abbastanza diffuso) tutto quello detto finora gli risulterà indifferente, magari addirittura fastidioso. Ma magari non dovrebbe leggere questo blog, sarà capitato qui per sbaglio.

Ciao e al prossimo post!