Programmare con stile (5)

misc41.jpg

Siamo giunti all’ultima puntata di Programmare con stile. Come ultima questione analizzeremo l’importanza di un corretto uso di macro preprocessore. Le macro sono utilizzate per definire costanti o etichette, ma anche per gestire flussi condizionali durante la fase di compilazione. Vediamo come utilizzarle in maniera ottimale.

Capitolo 8: Macro preprocessore

I nomi di macro che definiscono costanti devono essere tutti in maiuscolo.

#define CONSTANT 0x12345

Quando, invece, si definiscono più costanti in relazione fra loro è preferibile utilizzare “enum”.

I nomi di macro in maiuscolo sono molto apprezzati, ma è preferibile scrivere in minuscolo le macro che definiscono funzioni.

In generale è preferibile utilizzare funzioni “inline” al posto di funzioni definite come macro.

Macro con più righe dovrebbero essere racchiuse in un blocco “do – while”.

#define macrofun(a, b, c)                       \
        do {                                    \
                if (a == 5)                     \
                        do_this(b, c);          \
        } while (0)

Alcune cose da evitare quando si scrivono macro:

1) Macro che includono controlli di flusso:

#define FOO(x)                                  \
        do {                                    \
                if (blah(x) < 0)                \
                        return -EBUGGERED;      \
        } while(0)

è un’implementazione SBAGLIATA. Sembra una chiamata di funzione, ma in realtà fa uscire dalla funzione dove viene chiamata; crea grande confusione ai programmatori che leggeranno il codice.

2) Macro che dipendono dall’avere una variabile locale con un nome noto

#define FOO(val) bar(index, val)

può apparire come un’ottima pensata, ma è dannatamente confusionaria per chi legge il codice ed è a rischio di errori con alcune innocenti modifiche del codice.

3) Macro con argomenti usati come assegnamento

FOO(x) = y;

questo ti procurerà problemi se qualcuno, ad esempio, convertirà FOO in una funzione inline.

4) Dimenticarsi delle precedenze

#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)

Le macro che definiscono costanti attraverso espressioni devono racchiudere tali operazioni fra parentesi. Fai attenzione a problemi simili con macro che usano parametri. Il manuale del preprocessore cpp e il manuale del compilatore gcc trattano delle macro in maniera esaustiva.

Abbiamo visto che anche nella definizione di macro si possono prendere accorgimenti per programmare in maniera elegante evitanto molto spesso gravi errori. Come nota personale vorrei aggiungere che dall’esperienza che ho avuto nella programmazione kernel ho sempre portato con me un piccolo trucco/macro per commentare un blocco di codice. Basterà racchiudere un blocco fra “#if 0” e “#endif” che si forzerà il preprocessore a non compilare quel pezzo di codice. Inoltre, editor seri (chi ha detto Vim?🙂 ) hanno già la sintassi abilitata per riconoscere quel particolare blocco come commento.

La guida termina qui, con la promessa che sarà disponibile interamente in formato PDF scaricabile da questo sito. Permettetemi di aggiungere che, avendo la sfrenata mania di divulgare informazioni, mi piacerebbe poter realizzare una conferenza su queste ed altre cose…chi fosse interessato può scrivermi a vellei@libero.it.

Parte 4

4 pensieri su “Programmare con stile (5)

  1. #if #else #endif #ifdef #define … ah muscia x le mie orecchie

    ti segnalo un’altra direttiva di preprocessing, il #pragma, che permette di definire regioni di codice (che fanno una qualche operazione). se usi visual studio, puoi scrivere
    #pragma region NOME

    #pragma endregion
    e magicamente il tratto di codice si può espandere e nascondere (a livello di editor, precisiamo). tra l’altro le direttive #pèragma vengono ignorate da gcc, quindi potete usarle tranquillamente se svilupptae in C multipiattaforma.

  2. @arwenh:
    I #pragma dipendono strettamente dall’architettura che stai programmando, solitamente servono per dare direttive di copilazione riguardo a sezioni di codice. Nella scrittura di firmware, ad esempio, sono usatissime per posizionare i diversi blocchi di codice sulle relative sezioni di flash.

    In realtà il gcc non ignora le direttive #pragma. Ad esempio nel kernel Linux sono usate per definire l’allineamento in byte di alcune strutture ( #pragma pack(x) ).

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...