2013-08-06 12 views
5

Sto leggendo un argomento di posta elettronica per quanto riguarda la seguente riga di codice:ANSI C in realtà specifica quali byte vengono utilizzati quando si esegue il typecasting su un numero intero più piccolo?

p = (unsigned char)random(); 

La funzione random restituisce un lungo, e qualcuno dice che questo non è sicuro perché è possibile che il typecast potrebbe prendere il MSB, invece di l'LSB. So che su x86 il typecast restituirà LSB, ma non riesco a trovare alcuna informazione sul fatto che questo sia effettivamente richiesto da ANSI C o se è uno di quei "comportamenti non definiti" specifici dell'implementazione.

+1

La domanda è interessante e la risposta vale la pena conoscere, ma nel codice reale, si dovrebbe cercare di rimuovere la confusione. In altre parole, se si cambia il codice in questo modo, non c'è dubbio su quale byte viene utilizzato: 'p = (unsigned char) (random()% 256)'. Ciò impedirà a qualsiasi futuro lettore del tuo codice di chiedersi la stessa cosa. Come regola generale, non si dovrebbe scrivere codice che si basi sulla conoscenza dettagliata degli standard per comprendere. –

+0

In effetti il ​​cast non è necessario; è possibile assegnare qualsiasi tipo numerico a qualsiasi altro tipo numerico e verrà convertito implicitamente come se fosse un cast. –

+0

@KeithThompson: i compilatori possono avvisare se una conversione potenzialmente lossy viene utilizzata senza cast, sebbene ... – Christoph

risposta

6

Questo è specificato nello standard C.

C99 in 6.3.1.3p2 dice:

"Altrimenti, se il nuovo tipo è senza segno, il valore viene convertito ripetutamente aggiungendo o sottraendo un superiore al valore massimo che può essere rappresentato nel nuovo digitare finché il valore non si trova nell'intervallo del nuovo tipo. "

Su un sistema a complemento a due, significa prendere i bit meno significativi.

+0

Ma per la conversione in un tipo * signed *, se il tipo di destinazione non può rappresentare il valore il risultato è definito dall'implementazione (oppure può generare un segnale definito dall'implementazione, ma non conosco nessun compilatore che lo faccia). –

+0

@KeithThompson: in che modo la documentazione di un'implementazione deve descrivere il comportamento? Potrebbe un'implementazione legittimamente specificare che assegnando direttamente a un tipo firmato a 16 bit un valore N al di fuori dell'intervallo -32768..32767 memorizzerà qualcosa che si comporterà come N + 65536 * __ INDETERMINATE_VALUE, ma che un typecast esplicito a un 16 bit con segno tipo memorizzerà la rappresentazione canonica? – supercat

+0

@supercat: in entrambi i casi, c'è una conversione; un cast (non "typecast") specifica solo la stessa conversione che sarebbe stata eseguita implicitamente in assenza del cast. Sto assumendo qualcosa come 'int n = too_big;' vs. 'int n = (int) too_big;'. In qualsiasi implementazione * sana *, entrambe le conversioni produrranno lo stesso risultato, e sospetto che il comitato standard abbia ritenuto che fosse così. Ma immagino che la formulazione lasci un po 'di spazio di manovra: "... il risultato è definito dall'implementazione o viene generato un segnale definito dall'implementazione." (N1570 6.3.1.3p3) –