Rappresentazione dei dati: binario, esadecimale, complemento a due e caratteri
Sistema binario ed esadecimale, complemento a due, overflow in C con esempi, tipi a larghezza fissa, virgola fissa, ASCII e UTF-8, operatori sui bit.
Dentro un computer tutto è fatto di bit: numeri, lettere, immagini, istruzioni. Lo stesso gruppo di 8 bit, 01000001, può essere il numero 65, la lettera A o un pezzo di un’istruzione, a seconda di come lo si interpreta. In questa lezione vediamo come si rappresentano i numeri interi con e senza segno, il complemento a due, la notazione esadecimale, i caratteri e i problemi di overflow che ne derivano.
Il sistema binario
In base 2 ogni cifra vale una potenza di 2:
. Per convertire un numero decimale in binario si divide ripetutamente per 2 e si leggono i resti dal basso: 13 → 6 resto 1, 3 resto 0, 1 resto 1, 0 resto 1, quindi
.
Con
bit si rappresentano
valori: con 8 bit (un byte) da 0 a 255, con 16 bit da 0 a 65 535, con 32 bit da 0 a circa 4,3 miliardi.
L’esadecimale
I numeri binari sono lunghi e difficili da leggere. La base 16 usa le cifre 0-9 e A-F (A = 10, …, F = 15), e ogni cifra esadecimale corrisponde esattamente a 4 bit. La conversione è immediata, a gruppi di quattro:
| Binario | 1010 | 0011 | 1111 | 0000 |
|---|---|---|---|---|
| Esadecimale | A | 3 | F | 0 |
Quindi
. In C i numeri esadecimali si scrivono con il prefisso 0x. Gli indirizzi di memoria, i colori nelle pagine web (#FF8000) e i valori dei registri nei datasheet si scrivono in esadecimale.
Numeri con segno: il complemento a due
Il modo naturale di rappresentare i negativi, un bit di segno e il modulo, ha due difetti: due zeri (+0 e −0) e circuiti di somma diversi per i positivi e i negativi. Tutti i processori usano invece il complemento a due: con
bit, il bit più significativo pesa
invece di
.

Con 4 bit:
. Gli intervalli sono da
a
: con 8 bit da −128 a 127, con 32 bit da circa −2,1 a +2,1 miliardi.
Come si cambia segno. Si invertono tutti i bit e si somma 1. Da
: inverto, 1010; sommo 1, 1011 = −5. Verifica:
, e il riporto oltre il quarto bit si scarta: 0.
Il vantaggio. La somma funziona allo stesso modo per positivi e negativi: lo stesso circuito sommatore fa
sommando
, cioè 4 scartando il riporto. La sottrazione diventa la somma dell’opposto.
L’overflow
Se il risultato non sta nei bit disponibili, “fa il giro” della ruota. Con 8 bit con segno,
. In C:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint8_t u = 250;
u = u + 10; /* senza segno: 260 - 256 = 4 */
printf("%u\n", u); /* stampa 4 */
int16_t t = 30000;
t = t + 10000; /* con segno: il risultato non sta in 16 bit */
printf("%d\n", t); /* su quasi tutti i sistemi stampa -25536 */
return 0;
}
Per i tipi senza segno il C garantisce l’aritmetica modulo
. Per quelli con segno l’overflow è un comportamento non definito: il compilatore può assumere che non avvenga, e i risultati possono essere sorprendenti. È una delle sorgenti di bug più comuni nel firmware: un contatore di millisecondi a 32 bit senza segno torna a zero dopo circa 49,7 giorni, e il codice che confronta i tempi deve tenerne conto.
I tipi a larghezza fissa di <stdint.h> (uint8_t, int16_t, uint32_t, …) sono da preferire nei programmi per microcontrollori, perché la dimensione di int cambia da un processore all’altro: 16 bit su un AVR, 32 su un ARM.
I numeri reali
I numeri con la virgola si rappresentano in virgola mobile secondo lo standard IEEE 754 (tipi float e double in C), descritto nella lezione di Calcolo numerico sugli errori. Nei microcontrollori senza unità di calcolo in virgola mobile si usa spesso la virgola fissa: si lavora con interi che rappresentano, per esempio, millesimi (una tensione di 3,301 V diventa 3301 mV).
I caratteri
Un carattere è un numero secondo una tabella di codifica. Il codice ASCII (1963) usa 7 bit per 128 caratteri: ‘A’ = 65, ‘a’ = 97, ‘0’ = 48, lo spazio = 32, il ritorno a capo = 10. In C un char è un piccolo intero, e si può fare aritmetica sui caratteri: '7' - '0' vale 7, ed è il modo standard di convertire una cifra in numero.
Per tutti gli alfabeti del mondo c’è Unicode, con oltre 150 000 caratteri, codificato quasi sempre in UTF-8: i caratteri ASCII occupano un byte, le lettere accentate due (è = 0xC3 0xA8), gli ideogrammi tre, le emoji quattro. È per questo che una stringa C con “perché” occupa 7 byte e non 6.
Gli operatori sui bit
Il C permette di lavorare sui singoli bit con gli operatori & (AND), | (OR), ^ (XOR), ~ (NOT), << e >> (scorrimento). Uno scorrimento a sinistra di
posizioni moltiplica per
: x << 3 vale x * 8. Sono fondamentali per i protocolli di comunicazione e per i registri delle periferiche, come vedremo nella lezione sul C per i sistemi embedded.




