Qualificatori di Tipo e Suffissi in Linguaggio C
Argomenti: modificatori di ampiezza e segno, operatore sizeof(), suffissi delle costanti, prevenzione dell'overflow, tipi stdint.h
I tipi di dato base del C (come int e double) non sempre bastano: a volte serve risparmiare RAM su sistemi embedded, oppure memorizzare numeri astronomici che supererebbero i 2 miliardi. Per controllare con precisione **memoria, segno e intervallo di valori**, il C mette a disposizione i qualificatori di tipo e i suffissi per le costanti.
1. I Qualificatori per Tipi Interi
Modificatori: Come variare la dimensione (short, long, long long) ed il segno (unsigned)
| Tipo Modificato | Descrizione e Intervallo Tipico | Byte Tipici | Spec. printf |
|---|---|---|---|
short int (o solo short) |
Intero ridotto con segno. Range: da $-32.768$ a $+32.767$. Ideal per array grandi. | 2 Byte (16 bit) | %hd |
int |
Intero standard con segno. Range: da $-2,1 imes 10^9$ a $+2,1 imes 10^9$. | 4 Byte (32 bit) | %d oppure %i |
unsigned int (o solo unsigned) |
Intero senza segno (solo numeri $\ge 0$). Raddoppia il massimo positivo: da $0$ a $+4,2 imes 10^9$. | 4 Byte (32 bit) | %u |
long int (o solo long) |
Intero lungo con segno. Garantito almeno 4 Byte (spesso 8 Byte su Linux 64 bit). | 4 o 8 Byte | %ld |
unsigned long |
Intero lungo senza segno. Intervallo positivo esteso (fino a $1,8 imes 10^{19}$ su 64 bit). | 4 o 8 Byte | %lu |
long long int (C99) |
Intero ultra-capiente a 64 bit. Range: da $-9 imes 10^{18}$ a $+9 imes 10^{18}$. Utile per timestamp o monete virtuali. | 8 Byte (64 bit) | %lld |
L'importanza di unsigned
Un bit dei numeri standard viene riservato per memorizzare il segno (+ o -). Rimuovendo i numeri negativi con unsigned, quel bit viene usabile per il valore, raddoppiando l'intervallo positivo. È perfetto per contatori, indici, dimensioni e conteggi di oggetti fisici che non possono mai essere negativi.
La Catena di Garanzia delle Dimensioni
Lo standard C non impone la dimensione esatta in Byte, ma garantisce una gerarchia precisa:
sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)
2. Suffissi per le Costanti Numeriche (Literals)
Tipi Espliciti: Forzare il tipo esatto dei numeri scritti a mano nel codice
I numeri scritti direttamente nel sorgente (es. 100 o 3.14) hanno un tipo implicito assegnato dal compilatore. Aggiungendo un suffisso in coda al numero, si indica in modo inequivocabile come allocarlo:
Suffissi per Numeri Decimali
foppureF➔ Forza il valore afloat(4 Byte):float x = 3.14f;(evita warning da double).loppureL➔ Forza il valore along double(8, 10 o 16 Byte):long double p = 3.141592653589793238L;
Suffissi per Numeri Interi
uoppureU➔ Intero senza segno (unsigned int):4000000000UloppureL➔ Intero lungo (long int):3000000000LlloppureLL➔ Intero a 64 bit (long long):9000000000000LLuloppureUL➔ Combinato senza segno lungo:5000000000UL
3. Laboratorio Pratico: Misurare i Tipi con sizeof()
Strumenti: Operatore sizeof(), libreria <limits.h> e stampa dinamica
| 1 | #include <stdio.h> |
| 2 | #include <limits.h> // Contiene le costanti limite (es. INT_MAX) |
| 3 | |
| 4 | int main(void) { |
| 5 | printf("=== ANALISI DEGLI INTERI === "); |
| 6 | printf("short: %zu byte | Max: %d ", sizeof(short), SHRT_MAX); |
| 7 | printf("int: %zu byte | Max: %d ", sizeof(int), INT_MAX); |
| 8 | printf("unsigned int: %zu byte | Max: %u ", sizeof(unsigned), UINT_MAX); |
| 9 | printf("long: %zu byte | Max: %ld ", sizeof(long), LONG_MAX); |
| 10 | printf("long long: %zu byte | Max: %lld ", sizeof(long long), LLONG_MAX); |
| 11 | |
| 12 | // Esempio con costante con suffisso |
| 13 | unsigned long long popMondiale = 8000000000ULL; |
| 14 | printf("Popolazione: %llu persone ", popMondiale); |
| 15 | |
| 16 | return 0; |
| 17 | } |
- Specificatore
%zu: L'operatoresizeof()restituisce un tipo speciale chiamatosize_t. Il suo specificatore di stampa corretto inprintfè%zu. - Libreria
<limits.h>: Fornisce le costanti che indicano i limiti del tuo compilatore (es.INT_MAX,SHRT_MAX,LLONG_MAX). - Suffisso
ULL(riga 13): Indica che la costante `8000000000` è un `unsigned long long` a 64 bit, prevenendo errori di troncamento durante la compilazione.
4. Integer Overflow e i Tipi Moderni (<stdint.h>)
Sicurezza del Codice: Cosa succede se si supera il limite e come scrivere codice portabile
Che cos'è l'Integer Overflow?
Se aggiungi 1 a una variabile che ha già raggiunto il suo valore massimo gestibile, si verifica un overflow. Nei tipi unsigned, il valore fa un "giro completo" e torna a 0.
unsigned short x = 65535;x = x + 1; // x diventa 0!
I Tipi a Dimensione Fissa (<stdint.h>)
Poiché la dimensione di int e long può variare tra PC, Linux ed Embedded, dallo standard C99 esiste la libreria <stdint.h> con tipi a bit garantiti:
- int8_t / uint8_t (Esattamente 1 Byte / 8 bit)
- int16_t / uint16_t (Esattamente 2 Byte / 16 bit)
- int32_t / uint32_t (Esattamente 4 Byte / 32 bit)
- int64_t / uint64_t (Esattamente 8 Byte / 64 bit)
Come orientarsi nella scelta quotidiana?
• Per la stragrande maggioranza dei numeri interi quotidiani, usa int.
• Se stai lavorando con indici di array, contatori o dimensioni di memoria, usa unsigned o size_t.
• Se devi gestire timestamp, ID di database o quantità monetarie in centesimi, usa long long o int64_t.
In sintesi
Argomenti: concetti principali, riepilogo, competenze
- I qualificatori (short, long, long long, unsigned) modificano l'intervallo di valori e l'occupazione di memoria dei tipi interi.
- L'uso di unsigned elimina i numeri negativi raddoppiando il valore massimo positivo gestibile.
- I suffissi (F, L, U, LL) comunicano al compilatore il tipo esatto delle costanti letterali scritte nel codice.
- L'operatore sizeof() restituisce la dimensione reale in Byte dei tipi di dato sul sistema in uso.
- Distinguere l'uso e i limiti di short, int, long, long long ed unsigned.
- Utilizzare lo specificatore di formato corretto in printf/scanf (%d, %u, %ld, %lld, %zu).
- Applicare i suffissi alle costanti letterali per evitare troncamenti o conversioni indesiderate.
- Comprendere il fenomeno dell'Integer Overflow e l'uso pratico di <stdint.h> (int32_t, uint64_t).