Cosa dovrebbe significare il casting?


18

Quando si codifica in linguaggi di basso livello come CI, a volte si scopre che casting significa "reinterpretare questi byte come se fosse sempre stato di questo altro tipo" e altre volte come "convertire questo valore in modo intelligente in questo altro tipo".

Qual è il significato originale della parola e c'è coerenza in quando aspettarsi una conversione e quando aspettarsi una reinterpretazione grezza?


cos'è l' articolo di Wikipedia che non capisci? "la conversione del tipo , la tipografia e la coercizione sono modi diversi di modificare implicitamente o esplicitamente un'entità di un tipo di dati in un altro ... Ogni linguaggio di programmazione ha le sue regole su come convertire i tipi ..."
gnat

Il significato originale di "lanciare" non ha nulla in comune con la programmazione, vedere qui merriam-webster.com/dictionary/cast
Doc Brown,

1
Molto (soprattutto dal punto di vista della lingua gestita) sul blog di Eric Lippert nella categoria degli operatori del cast
AakashM,

1
@gnat: non sono sicuro che si tratti di una domanda seria o di un tentativo di pesca a traina. Ma vorrei sapere come farà il compilatore: convertire, trasmettere o forzare? Quali sono le regole empiriche?
Alexander Torstling,

1
@DocBrown Penso che il termine castin senso informatico sia più simile al casting in senso metallurgico, per cui la forma di un metallo fuso viene riformata quando viene versata in uno stampo: britannica.com/EBchecked/topic/377665/metallurgy/81884/Casting
KChaloux,

Risposte:


10

Il cast in C è unico, abbastanza diverso dalle altre lingue. Inoltre non è mai intelligente.

La fusione in C converte i valori da un tipo a un altro usando regole accuratamente definite. Se hai davvero bisogno di sapere, leggi lo standard. Altrimenti i punti principali sono:

  1. La conversione tra tipi interi conserva il valore, se possibile. Se la destinazione ha più bit, questo si sta allargando e generalmente è sicuro, ma può comportare l'estensione del segno. Se più stretto, i bit andranno persi.
  2. La conversione tra i tipi di puntatore conserva il valore del puntatore, ma i risultati sono spesso indefiniti, spesso non portatili e spesso utili per scenari avanzati.
  3. La conversione tra tipi di numeri interi e puntatori è OK se l'intero è abbastanza grande e conserva il modello di bit (qualunque cosa ciò possa significare). Se il numero intero è troppo piccolo, il risultato è indefinito ma non utile. Di norma "long" è abbastanza largo per "void *", ma nessuna garanzia! I puntatori creati in questo modo potrebbero non essere validi, in tutti i modi interessanti.
  4. Le conversioni tra tipi float e interi sono conversioni aritmetiche definite da una routine di libreria appropriata (con troncamento, non arrotondamento).
  5. È possibile annullare il valore restituito di una funzione. Non ho mai. Non fa niente.

Alcuni cast vengono applicati implicitamente e in alcuni di questi il ​​compilatore emetterà un avviso. Meglio prestare attenzione agli avvertimenti!

È meglio ignorare la definizione del dizionario per cast, in quanto non utile. Molti cast sono meglio descritti dai termini conversione o coercizione, quindi vale la pena conoscerli.

Il C ++ è MOLTO più complicato, ma non l'hai chiesto, vero?


Sono interessato alle regole empiriche e non a dettagli minuscoli, ma mi interessano altre lingue oltre a C se questo aiuta a chiarire le cose.
Alexander Torstling,

2
Quello che ho dato qui è generico quanto ragionevole. Per scrivere codice C / C ++ professionale reale di basso livello, i dettagli minuscoli sono fondamentali. La maggior parte delle lingue non ha questo tipo di problema nelle conversioni di tipo. Scusa se non risolve il tuo problema.
david.pfx,

Solo che la conversione da T*a void*e ritorno è sempre ben definito.
Miles Rout il

@Miles: in realtà, è necessario convertire T * in qualsiasi U * e viceversa per preservare il valore del puntatore originale. Nella mia risposta ho solo detto "spesso indefinito" per farla breve, perché alcuni dettagli sono molto disordinati.
david.pfx,

1
@supercat: vedi n. 1570 S6.3.2.3. La conversione / round-trip tra T *, U * e void * conserva sempre il valore del puntatore con una sola eccezione. Se qualsiasi T * non è allineato correttamente, si tratta di un comportamento indefinito. Accetto il tuo punto, ma solo fino a quel punto.
david.pfx,

2

Questa parte del dizionario Webster fornisce la definizione corretta:

a: dare una forma a (una sostanza) versando in forma liquida o plastica in uno stampo e lasciando indurire senza pressione
b: formare con questo processo

Quindi, prima del casting, il tuo "oggetto" (non letteralmente un oggetto OOP) ha una determinata forma (tipo). Quando lo rilasci, questo è "versare cemento" attorno ad esso per renderlo in una nuova forma, questo è ciò che fai con il casting. Hai un numero come numero intero a forma esagonale e dopo il lancio otterrai una stringa a forma di rettangolo.


2
Inoltre : "Per assegnare un determinato ruolo a (un attore)".
Kelly Thomas,

Sì. Sono sicuro che questo è il migliore. +1.
david.pfx,

2

Può essere utile separare i cast C in due gruppi:

  1. Cast numerici: converti un numero tra una rappresentazione in un'altra, cercando di mantenere il valore. Ad esempio - (int)3.1sarebbe 3. Ci sono regole esatte che definiscono cosa succede quando il valore esatto non può essere mantenuto.

  2. Lancia il puntatore - Mantieni l'indirizzo di memoria, ma cambia il modo in cui è dereferenziato. Ad esempio, per float x=3.5, *(int *)&xdarà 1080033280- questo numero intero è rappresentato dallo stesso modello di bit che rappresenta il float 3.5.


Keep the memory address, but change the way it's dereferenced.Il dereferenziamento di un puntatore punzonato non è definito. Lo Standard garantisce solo che il lancio da e A *verso il B *retro produrrà lo stesso A *, che potrebbe non essere stato valido per il dereference in primo luogo - o che se B *è un char *, può essere usato per leggere la rappresentazione di oggetti di qualsiasi tipo. Per tutti gli altri tipi, il B *puntatore di dereferenziazione è di tipo punzonatura, UB e viola alias rigoroso. Ad ogni modo, anche se il compilatore non ha eliminato l'esempio 2 di cui sopra per questo motivo, stai facendo ipotesi insostituibili sui modelli di bit
underscore_d

1
cast (v): to receive form in a mold

In C ++ i vari tipi di cast possono essere resi più espliciti, con il reinterpret_castsignificato "tratta questi byte come se fossero già l'altra cosa". In C puoi renderlo assolutamente esplicito usando a union, il casting con l' (type)operatore tenterà di mantenere il risultato numericamente equivalente, fino alla perdita di precisione.


2
In C i cast di puntatori vengono sempre reinterpretati e i cast di valori conservano sempre il valore nel miglior modo possibile. In C ++ ci sono diversi modi per eseguire il cast del puntatore, motivo per cui esistono tipi di cast più espliciti.
Jan Hudec,

La semantica C pointer-cast non è necessariamente "reinterpretare". Sarebbe legittimo per un processore che utilizzava l'indirizzamento delle parole ma voleva interagire bene con il codice basato su byte per avere int*una parola che era una parola e una char*che era due parole [con il secondo byte che selezionava il byte alto o basso di una parola]. Lanciare un (int*)to (char*)richiederebbe l'aggiunta di una parola in più che dovrebbe essere qualunque valore specifichi il primo byte del int.
supercat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.