Costanti Intere in Linguaggio C

In questo articolo esploreremo la rappresentazione delle costanti numeriche intere nel linguaggio di programmazione C.

Discuteremo le diverse basi in cui queste costanti possono essere scritte: decimale, ottale, esadecimale e binaria. Inoltre, approfondiremo le regole per determinare il tipo di una costante intera a seconda della sua base numerica.

Valori numerici letterali interi in C

Nei programmi scritti in C sorge spesso l'esigenza di inserire delle costanti numeriche all'interno del codice sorgente.

Ad esempio, supponendo di voler realizzare un'istruzione if che confronti una variabile con un valore numerico, è possibile scrivere il seguente codice:

int numero;

printf("Inserisci un numero: ");
scanf("%d", &numero);

if (numero >= 100) {
    printf("Hai inserito un valore maggiore di 100\n");
}

In questo caso, il valore 100 è una costante numerica intera che viene confrontata con il valore inserito dall'utente. Tali costanti prendono anche il nome di valori numerici letterali.

In linguaggio C, i valori numerici letterali possono essere scritti in diverse basi numeriche:

  • Decimale: il formato più comune, in cui i numeri sono scritti con le cifre da 0 a 9.

  • Ottale: i numeri sono scritti solo con le cifre da 0 a 7.

    Ciascuna cifra di un numero ottale rappresenta una potenza del numero 8, proprio allo stesso modo in cui ciascuna cifra di un numero decimale rappresenta una potenza del numero 10.

    Per cui, ad esempio, il numero ottale 142 rappresenta il numero:

    1 \cdot 8^2 + 4 \cdot 8^1 + 2 \cdot 8^0 =
    1 \cdot 64 + 4 \cdot 8 + 2 \cdot 1 = 64 + 32 + 2 = 98
  • Esadecimale: i numeri sono scritti con le cifre da 0 a 9 e le lettere da A a F.

    Le lettere da A ad F indicano, rispettivamente, i numeri da 10 a 15. Anche in questo caso, ciascuna cifra di un numero esadecimale rappresenta una potenza del numero 16.

    Ad esempio, il numero esadecimale AB3 rappresenta il numero:

    A \cdot 16^2 + B \cdot 16^1 + 3 \cdot 16^0 =
    10 \cdot 256 + 11 \cdot 16 + 3 \cdot 1 = 2560 + 176 + 3 = 2739
  • Binaria: i numeri sono scritti solo con le cifre 0 e 1.

    Anche in questo caso, ciascuna cifra di un numero binario rappresenta una potenza del numero 2.

    Ad esempio, il numero binario 1011 rappresenta il numero:

    1 \cdot 2^3 + 0 \cdot 2^2 + 1 \cdot 2^1 + 1 \cdot 2^0 =
    1 \cdot 8 + 0 \cdot 4 + 1 \cdot 2 + 1 \cdot 1 = 8 + 0 + 2 + 1 = 11

In linguaggio C, per poter scrivere una costante numerica in una base diversa dalla decimale, è necessario anteponere un prefisso che indichi la base numerica utilizzata. Questo perché il compilatore deve essere in grado di riconoscere la base numerica della costante.

I prefissi sono i seguenti:

  • Numeri ottali: il prefisso è 0 (zero).

    Ad esempio, il numero ottale 142 si scrive in C come 0142. Di seguito, alcuni esempi di numeri ottali:

    • 012 (10 in decimale)
    • 034 (28 in decimale)
    • 077 (63 in decimale)
  • Numeri esadecimali: il prefisso è 0x o 0X.

    Ad esempio, il numero esadecimale AB3 si scrive in C come 0xAB3. Di seguito, alcuni esempi di numeri esadecimali:

    • 0x0A (10 in decimale)
    • 0x1F (31 in decimale)
    • 0x7F (127 in decimale)

    Un importante dettaglio che riguarda le costanti esadecimali è che le lettere possono essere scritte sia in maiuscolo che in minuscolo.

    Ad esempio, i seguenti valori sono equivalenti:

    • 0xAB3 è uguale a 0xab3
    • 0x1F è uguale a 0x1f

    Inoltre, maiuscole e minuscole possono essere mescolate all'interno dello stesso valore:

    • 0xDaF è uguale a 0xdAf
  • Numeri binari: il prefisso è 0b o 0B.

    Ad esempio, il numero binario 1011 si scrive in C come 0b1011. Di seguito, alcuni esempi di numeri binari:

    • 0b0001 (1 in decimale)
    • 0b1010 (10 in decimale)
    • 0b1111 (15 in decimale)

Ricapitolando:

Definizione

Costanti numeriche intere in C

Le costanti numeriche intere in C possono essere scritte in diverse basi numeriche anteponendo un prefisso che indichi la base utilizzata:

  • Decimale: senza prefisso e cifre da 0 a 9;
  • Ottale: prefisso 0 e cifre da 0 a 7;
  • Esadecimale: prefisso 0x o 0X e cifre da 0 a 9 e lettere da A a F;
  • Binaria: prefisso 0b o 0B e cifre 0 e 1.

Bisogna tenere presente che scrivere costanti numeriche in base ottale, esadecimale e binaria non comporta alcuna differenza per il compilatore ed il processore. I numeri vengono comunque rappresentati (e quindi convertiti) in base binaria per essere elaborati.

Possiamo passare da una notazione all'altra senza problemi nei nostri programmi. Addirittura, possiamo mescolare costanti numeriche scritte in basi diverse all'interno della stessa espressione.

Possiamo, ad esempio, scrivere il seguente codice, perfettamente valido:

int risultato;

risultato = 23 + 0x1F + 0b1011 + 012;

In questo caso, il valore della variabile risultato sarà uguale a 23 + 31 + 11 + 10 = 75.

Utilizzare le notazioni ottale, esadecimale e binaria risulta molto conveniente quando si scrivono programmi che manipolano dati a basso livello. Ad esempio quando si scrivono programmi che si interfacciano direttamente con l'hardware o con il sistema operativo.

Per il momento tralasceremo queste notazioni, concentrandoci sulle costanti numeriche scritte in base decimale. Utilizzeremo le notazioni ottale, esadecimale e binaria in seguito, quando affronteremo argomenti più avanzati.

Tipo delle costanti numeriche

Abbiamo visto nella lezione precedente che il linguaggio C mette a disposizione una serie di tipi di dati interi, come int, short, long, long long, che differiscono per la quantità di memoria che occupano, per il fatto che possono essere con o senza segno, e per il range di valori che possono rappresentare.

Quello che ci domandiamo, adesso, è: qual è il tipo di una costante numerica intera scritta in un programma C?

Lo standard del C e, di conseguenza, i compilatori seguono una serie di regole per determinare il tipo di una costante numerica intera. Queste regole differiscono in base alla base numerica in cui la costante è scritta.

Se le costanti numeriche sono scritte in base decimale le regole sono le seguenti:

  • Di default la costante è di tipo int;
  • Se il suo valore è troppo grande per essere rappresentato con un int, allora è di tipo long int;
  • Se il suo valore è troppo grande per essere rappresentato con un long int, allora è di tipo unsigned long int che rappresenta l'ultima scelta.

Per cui la sequenza di scelta per una costante decimale è la seguente:

\texttt{int} \rightarrow \texttt{long int} \rightarrow \texttt{unsigned long int}

Nel caso in cui, invece, la costante è scritta in base binaria, ottale o esadecimale, le regole sono leggermente differenti:

  • Di default la costante è di tipo int;
  • Se il suo valore è troppo grande per essere rappresentato con un int, allora è di tipo unsigned int;
  • Allo stesso modo, se il suo valore è troppo grande per essere rappresentato con un unsigned int, allora è di tipo long int;
  • Infine, se il suo valore è troppo grande per essere rappresentato con un long int, allora è di tipo unsigned long int.

Per cui la sequenza di scelta per una costante binaria, ottale o esadecimale è la seguente:

\begin{array}{lclc} \texttt{int} && \rightarrow && \texttt{unsigned int} && \rightarrow \\ \texttt{long int} && \rightarrow && \texttt{unsigned long int} \end{array}
Definizione

Regole per il tipo delle costanti numeriche intere in C

Quando il compilatore C incontra una costante numerica intera, determina il suo tipo in base alla base numerica in cui è scritta.

Le regole partono da un tipo base e, se il valore della costante è troppo grande per essere rappresentato con quel tipo, passano al tipo successivo.

Tali regole costituiscono una sequenza di scelta che determina il tipo della costante numerica.

Se la base numerica è decimale, la sequenza di scelta è:

\texttt{int} \rightarrow \texttt{long int} \rightarrow \texttt{unsigned long int}

Se la base numerica è binaria, ottale o esadecimale, la sequenza di scelta è:

\begin{array}{lclc} \texttt{int} && \rightarrow && \texttt{unsigned int} && \rightarrow \\ \texttt{long int} && \rightarrow && \texttt{unsigned long int} \end{array}

Forzatura del tipo di una costante numerica

Piuttosto che affidarsi al compilatore, in C è possibile forzare il tipo di una costante numerica aggiungendo un suffisso al valore numerico.

I suffissi disponibili sono i seguenti:

  • u o U: forza il tipo della costante a unsigned int o unsigned long int;
  • l o L: forza il tipo della costante a long int o unsigned long int;

Tali suffissi possono essere combinati tra loro per ottenere il tipo desiderato.

Per cui, ad esempio, possiamo scrivere le seguenti costanti numeriche:

  • 123u: costante di tipo unsigned int;
  • 234U: costante di tipo unsigned int;
  • 123l: costante di tipo long int;
  • 234L: costante di tipo long int;
  • 123ul: costante di tipo unsigned long int.

Possiamo anche combinare i suffissi U e L con costanti scritte in basi diverse da quella decimale.

Ad esempio, possiamo scrivere le seguenti costanti numeriche:

  • 0x1Ful: costante esadecimale di tipo unsigned long int;
  • 0b1011u: costante binaria di tipo unsigned int.

Quando si utilizzano tali suffissi, non conta l'ordine in cui vengono scritti. Ad esempio, le seguenti costanti sono equivalenti:

  • 123ul è uguale a 123lu;
  • 0x1FUL è uguale a 0x1FLU.
Definizione

Forzatura del tipo di una costante numerica in C

Si può forzare, in linguaggio C, il tipo di una costante numerica apponendo un suffisso al valore:

  • u o U: forza il tipo a unsigned;
  • l o L: forza il tipo a long.

Tali suffissi possono essere combinati.

Regole per il tipo delle costanti numeriche in C99

In C99, come abbiamo visto, è stato introdotto il tipo aggiuntivo long long e unsigned long long.

Per tal motivo, le sequenze di scelta del tipo di una costante numerica intera si modificano leggermente.

Nel caso di una costante scritta in base decimale, la sequenza di scelta è la seguente:

\texttt{int} \rightarrow \texttt{long int} \rightarrow \texttt{long long int}

Mentre, nel caso di una costante scritta in base binaria, ottale o esadecimale, la sequenza di scelta è la seguente:

\begin{array}{lclc} \texttt{int} && \rightarrow && \texttt{unsigned int} && \rightarrow \\ \texttt{long int} && \rightarrow && \texttt{unsigned long int} && \rightarrow \\ \texttt{long long int} && \rightarrow && \texttt{unsigned long long int} \end{array}

Suffissi LL e ULL in C99

Oltre ai suffissi descritti sopra per forzare il tipo di una costante numerica, il C99 introduce due nuovi suffissi:

  • LL o ll: forza il tipo della costante a long long int;
  • ULL o ull: forza il tipo della costante a unsigned long long int.

Per cui, ad esempio, possiamo scrivere le seguenti costanti numeriche:

  • 123LL: costante di tipo long long int;
  • 234ULL: costante di tipo unsigned long long int.

In Sintesi

Questa lezione ci ha mostrato come rappresentare valori letterali interi, o costanti intere, in linguaggio C.

Abbiamo visto che tali costanti possono essere scritte in diverse basi numeriche: decimale, ottale, esadecimale e binaria. Abbiamo imparato a scrivere costanti numeriche in basi diverse da quella decimale, utilizzando i prefissi 0, 0x e 0b.

Abbiamo anche discusso delle regole che il compilatore C segue per determinare il tipo di una costante numerica, a seconda della base numerica in cui è scritta. Abbiamo visto che, in C, è possibile forzare il tipo di una costante numerica apponendo dei suffissi al valore.

Tali suffissi sono:

  • u o U: per forzare il tipo a unsigned;
  • l o L: per forzare il tipo a long;
  • LL o ll: per forzare il tipo a long long;
  • ULL o ull: per forzare il tipo a unsigned long long.

Nella prossima lezione studieremo come leggere e scrivere valori interi in C, utilizzando le funzioni scanf e printf. In particolare vedremo come leggere e scrivere i vari tipi di dati interi, come int, short, long e long long.