Skip to content

Conversioni Aritmetiche

Capita spesso di combinare tipi aritmetici diversi (es. sommare un int con un double). In questi casi, il C applica delle regole di conversione rigorose.

Il Cast ti permette di forzare manualmente il tipo di un’espressione mettendo il nuovo tipo tra parentesi:

int num_i = 5;
double num_d = (double)num_i; // Conversione esplicita

Spesso il compilatore effettua queste conversioni “dietro le quinte”. Per farlo segue un set di regole note come Usual Arithmetic Conversions:

  1. Integer Promotions (Promozioni Intere): I tipi interi piccoli (come char e short) vengono sempre “promossi” automaticamente ad int (o unsigned int) prima di fare somme, moltiplicazioni o valutare condizioni logiche. Questo previene gli overflow sulle variabili a 8 o 16 bit.
  2. Bilanciamento: Quando i due operandi sono di tipo diverso, il tipo più “debole” (di rango inferiore) viene convertito in quello più “forte”.
    • int + double → Il C converte l’int in double e fa la somma su due double.
    • signed int + unsigned int → L’operando signed viene “forzato” a diventare unsigned int.

Guardiamo un esempio spaventoso ma comune. Immagina di confrontare un -1 con il valore massimo UINT_MAX:

unsigned int ui = UINT_MAX;
signed char c = -1;
if (c == ui) {
printf("Magia, sono uguali!");
}

Perché stampa che sono uguali?

  1. Promozione: c è uno signed char (-1). Viene promosso a signed int (-1).
  2. Bilanciamento: Stiamo confrontando un signed int con un unsigned int. La regola dice che l’intero con segno deve convertirsi in intero senza segno.
  3. Il valore -1, letto come se fosse “senza segno” (quindi con tutti i bit a 1 nel complemento a due), corrisponde in memoria al valore binario equivalente a UINT_MAX. I due numeri combaciano a livello di bit!

Ecco un esercizio su una pericolosa conversione implicita. L’obiettivo di questo codice è scorrere un array. Tuttavia c’è una pericolosa combinazione di tipi: sizeof restituisce un tipo unsigned, che potrebbe far nascere dei bug con cicli che decrementano verso zero.