::Il-mio.sito-web-dedicato-al.coding   

... un quaderno delgi appunti! di Giuseppe VACCA

Linguaggio di programmazione C


Casting

 

Che cos'è il Casting

Nell'articolo sui puntatori è stato detto che ad ogni variabile è associato un tipo che definisce la dimensione dello spazio in memoria ad essa riservata, l'insieme delle operazioni che possono essere eseguite su di essa. Nello specifico è stata esaminata la variabile di tipo puntatore che contiene un valore numerico rappresentativo di un indirizzo di memoria.

Il casting è l'operazione che comporta la conversione di un tipo ad un altro.

L'operazione di casting è di due tipi:

  1. implicita: è il compilatore che converte in maniera automatica il tipo di una variabile;
  2. esplicita: è il programmatore che definisce come una variabile deve essere convertita mediante l'operatore di 'casting'

Assumiamo, in linea di principio, che non è possibile effettuare operazioni matematiche, o di altra natura, tra due operandi di diverso tipo. In pratica, però, ciò viene reso possibile dall'operazione di casting implicito.

Prendiamo in esame il seguente codice:

#include <stdio.h>

  void main() {

  int x = 5;
  float y = 2;

  float q = x / y;

  printf("%f\n", q);
}

Il rapporto tra variabile x ed y è un'operazione effettuata tra due valori numerici di tipo diverso:

  • x è una variabile di tipo intero;
  • y è una variabile di tipo a virgola mobile (float);

Il valore del loro rapporto è assegnato alla variabile q di tipo float(virgola mobile).

All'interno della espressione che calcola il rapporto la variabile x subisce una operazione di casting implicito: viene, in quel cotesto e solo in quel contesto, valutata come di tipo float. Questo accade nel rispetto di una regola di casting implicito per la quale il tipo meno preciso viene promosso al tipo di dato più preciso evitando errori nella compilazione e ottenendo un risultato più coerente. Questo non cambia il tipo originale della variabile, ma indica l'intezione di trattarla come float in quel contesto.

Il risultato dell'esecuzione sarà il seguente:

 

Fig.1 - Casting implicito

 

Il casting esplicito avviene mediante l'operatore di casting: esso è dato dalle parentesi tonde che racchiudono il nome del tipo nel quale si vuole convertire un variabile di diverso tipo:

(tipo_desiderato)valore

Operazione di casting esplicito:

#include <stdio.h>

  void main() {

  int x = 5;
  float b = (float) x;
  /*
    Alla variabile b viene assegnato il valore di x dopo che quest'ultia
    e' stata trasformata in float.
    La variabile originale x resta un tipo intero.
  */

  printf("%f\n", b);
}

Il risultato dell'esecuzione sarà il seguente:

 

Fig.1 - Casting esplicito

 

Anche in questo caso il tipo della variabile x rimene un intero. E' solo all'interno dell'operazione di creazione e assegnazione della variabile b che viene considerata un tipo float.

 

Casting da un intero a puntatore

A questo punto ci proponiamo di coinvolgere una variabile di tipo puntatore in una operazione di casting. Nello specifico convertire un intero in un puntatore. E' stato descritto sopra, in maniera generalizzata, l'utilizzo dell'operatore di casting. Qualora volessimo applicare l'operatore ad un'operazione che coinvolga una variabile di tipo puntatore dobbiamo tener conto, come accade ad esempio nella definizione di una variabile puntatore, del tipo di dato contenuto nella memoria a cui la variabile puntatore "punta". Pertanto, facendo riferimento alla regola sopra descritta, otterremo il seguente operatore di casting:

(int *)valore

  • int informa sul tipo di dato contenuto nell'indirizzo di memoria a cui la variabile puntatore "punta";
  • * indica che la variabile deve essere trasformata in puntatore;

E' importante sottolineare che l'operazione di casting, che coinvolge variabili di tipo puntatore, deve essere utilizzata con estrema cautela.

Esempio di casting di un decimale a puntaore:

#include <stdio.h>

void main() {

  int i;
  int *p;

  i = 90;

  p = (int *)i;

  printf("%p\n", p);

  /*
    Gli indirizzi di memoria vengono restituiti in notazione esadecimale
    pertanto l'output del programma sara' 0000005A (5A corrisponde al numero 90
    in notazione decimale).
  */
}

Il risultato dell'esecuzione sarà il seguente:

 

Fig.1 - Casting esplicito da intero a puntatore

 

IMPORTANTE: da tener presente in caso di casting da intero a puntatore

In merito a quanto detto prima sulla cautela con cui bisogna usare l'operazione di casting da inetero a puntatore bisogna sottolineare e ricordare alcuni aspetti:
allorquando un intero venga convertito in puntatore il problema principale è che un intero rappresenta un valore numerico, mentre un puntatore rappresenta un indirizzo di memoria - si sta essenzialmente dicendo al compilatore di trattare il valore intero come se fosse un indirizzo di memoria:

  1. il compilatore non verifica la validità dell'indirizzo intero convertito in puntatore - questo significa che se l'indirizzo intero non corrisponde a una posizione di memoria valida o accessibile, si potrebbe verificare un errore di segmentazione(*) o altri problemi simili durante l'esecuzione del programma;
  2. anche se l'indirizzo è valido, potrebbe puntare a dati non correlati, portando alla corruzione di informazioni importanti nel programma;
  3. in alcuni casi, il risultato del casting potrebbe essere imprevedibile e variare a seconda della piattaforma o del compilatore.

(*) errore di segmentazione: ha luogo quando un programma tenta di accedere ad una posizione di memoria alla quale non gli è permesso accedere, oppure quando tenta di accedervi in una maniera che non gli è concessa.