Direttive Varie del Preprocessore in Linguaggio C

Con questa lezione concludiamo lo studio del preprocessore del linguaggio C.

Vedremo qui le ultime tre direttive che il precompilatore mette a disposizione: #error, #line e #pragma.

Si tratta di direttive che vengono utilizzate raramente, ma che possono essere molto utili in determinate situazioni.

Direttiva #error

La direttiva di precompilazione #error ha la seguente sintassi:

#error messaggio

Dove messaggio è una sequenza di caratteri che rappresenta il messaggio di errore da visualizzare.

Quando il preprocessore incontra la direttiva #error, interrompe la compilazione e visualizza il messaggio di errore specificato.

Questa direttiva viene adoperata per indicare gravi problemi del programma in fase di compilazione. Infatti, essa viene adoperata sempre in congiunzione con la compilazione condizionale.

Vediamo un esempio. Supponiamo di scrivere un programma che non deve essere compilato per una macchina o sistema che non supporta il tipo floating point. In tal caso, possiamo utilizzare la direttiva #error per interrompere la compilazione e visualizzare un messaggio di errore.

#if !defined(__STDC_IEC_559__)
#error "Il sistema non supporta il tipo floating point"
#endif

In questo esempio, se il sistema non supporta il tipo floating point, la compilazione verrà interrotta e verrà visualizzato il messaggio "Il sistema non supporta il tipo floating point".

Analogamente, supponiamo che il nostro programma richieda che gli interi int siano memorizzati usando, almeno, 32 bit o 4 byte. Possiamo scriverere il seguente codice:

#include <limits.h>

#if INT_MAX < 2147483647
#error "Il tipo int è troppo piccolo"
#endif

Nel file limits.h sono definite le costanti INT_MAX e INT_MIN che rappresentano il valore massimo e minimo che un int può memorizzare. Se un intero int è rappresentato con 32 bit, allora il massimo che può memorizzare è:

2^{31} - 1 = 2147483647

Per cui, se INT_MAX è minore di 2147483647, allora il tipo int non utilizza 32 bit e la compilazione verrà interrotta con il messaggio "Il tipo int è troppo piccolo".

Spesso, la direttiva #error si trova nella clausola #else di una direttiva #if o #ifdef. Ad esempio:

#if defined(__linux__)
    /* Codice per Linux */
#else
    #error "Questo programma richiede un sistema operativo Linux"
#endif
Definizione

Direttiva #error

La direttiva di precompilazione #error interrompe la compilazione e visualizza un messaggio di errore specificato.

La sintassi è:

#error messaggio

Dove messaggio è il messaggio di errore da visualizzare.

Direttiva #line

La direttiva di precompilazione #line ha la seguente sintassi:

#line numero "file"

Questa direttiva è raramente utilizzata. Il suo scopo, infatti, è quello di modificare il valore delle macro __LINE__ e __FILE__. Per cui, ad esempio, se scriviamo:

#line 42 "file.c"

Da questo punto in poi, __FILE__ restituirà "file.c" e __LINE__ restituirà un valore progressivo a partire da 42.

La seconda conseguenza di questa direttiva, è che qualunque messaggio di errore mostrato dal compilatore indicherà come file file.c e come numero di riga il numero ottenuto dal numero di righe che seguono la direttiva #line più 42.

Perché utilizzare una direttiva di questo tipo? In generale, essa non viene mai utilizzata dagli sviluppatori, ma è utile per i tool di sviluppo e di debug.

Esistono svariati tool che generano codice C. Ad esempio, i parser di linguaggi di programmazione, i compilatori di linguaggi di markup, i tool di generazione di codice, ecc. Questi tool possono utilizzare la direttiva #line per indicare al compilatore la posizione del codice generato all'interno del file sorgente originale.

Possiamo immaginare, ad esempio, un tool che prende in ingresso un file scritto in un linguaggio chiamato linguaggioX e genera un file C. Supponiamo che questo tool prenda in ingresso un file con estensione .x e generi un file con estensione .c. In tal caso, il tool potrebbe utilizzare la direttiva #line per indicare al compilatore la posizione del codice generato all'interno del file .x:

#line 10 "file.x"

In questo modo, se il compilatore trova un errore nel file.c, il tool può mappare l'errore alla riga corrispondente nel file.x.

Definizione

Direttiva #line

La direttiva di precompilazione #line modifica il valore delle macro __LINE__ e __FILE__.

La sintassi è:

#line numero "file"

Dove numero è il numero di riga e file è il nome del file.

Direttiva #pragma

L'ultima direttiva di precompilazione che vedremo è #pragma. Questa direttiva è utilizzata per fornire informazioni al compilatore o per controllare il comportamento del compilatore.

La sintassi è:

#pragma comando

Attraverso di essa, possiamo passare comandi specifici al compilatore. Tuttavia, tali comandi non sono standardizzati e possono variare da compilatore a compilatore. Per cui, per conoscere quali sono conviene sempre consultare la documentazione del compilatore che si sta utilizzando.

Lo standard C99 introduce dei comandi standardizzati per la direttiva #pragma. Li vedremo nel dettaglio in seguito.

Definizione

Direttiva #pragma

La direttiva di precompilazione #pragma è utilizzata per inviare comandi specifici al compilatore.

La sintassi è:

#pragma comando

I comandi specifici possono variare da compilatore a compilatore.

In Sintesi

Con questa lezione abbiamo concluso il nostro studio del precompilatore C.

Abbiamo studiato le tre direttive rimanenti: #error, #line e #pragma.

  • La direttiva #error interrompe la compilazione e visualizza un messaggio di errore.

    Essa viene utilizzata per indicare gravi problemi del programma in fase di compilazione e viene sempre usata in congiunzione con la compilazione condizionale.

  • La direttiva #line modifica il valore delle macro __LINE__ e __FILE__. Inoltre, modifica il modo in cui il compilatore conteggia le righe e i file.

    Essa è utilizzata raramente dagli sviluppatori, ma è utile per i tool di sviluppo e di debug.

  • La direttiva #pragma è utilizzata per inviare comandi specifici al compilatore.

    I comandi specifici possono variare da compilatore a compilatore.