La mia domanda è simile a this ma un po 'più specifica. Sto scrivendo una funzione per leggere un intero senza segno a 32 bit da un istream rappresentato usando little endian. In C qualcosa di simile a questo dovrebbe funzionare:Comportamento non definito quando si utilizza iostream letto e firmato char
#include <stdio.h>
#include <inttypes.h>
uint_least32_t foo(FILE* file)
{
unsigned char buffer[4];
fread(buffer, sizeof(buffer), 1, file);
uint_least32_t ret = buffer[0];
ret |= (uint_least32_t) buffer[1] << 8;
ret |= (uint_least32_t) buffer[2] << 16;
ret |= (uint_least32_t) buffer[3] << 24;
return ret;
}
Ma se provo a fare qualcosa di simile utilizzando un istream
mi imbatto in quello che penso è un comportamento indefinito
uint_least32_t bar(istream& file)
{
char buffer[4];
file.read(buffer, sizeof(buffer));
// The casts to unsigned char are to prevent sign extension on systems where
// char is signed.
uint_least32_t ret = (unsigned char) buffer[0];
ret |= (uint_least32_t) (unsigned char) buffer[1] << 8;
ret |= (uint_least32_t) (unsigned char) buffer[2] << 16;
ret |= (uint_least32_t) (unsigned char) buffer[3] << 24;
return ret;
}
Si tratta di un comportamento indefinito nei sistemi in cui char è firmato e non c'è un complemento a due e non può rappresentare il numero -128, quindi non può rappresentare 256 caratteri diversi. In foo
funzionerà anche se il carattere è firmato perché la sezione 7.21.8.1 dello standard C11 (bozza N1570) dice che fread
utilizza unsigned char
non char
e unsigned char
deve essere in grado di rappresentare tutti i valori compresi nell'intervallo compreso tra 0 e 255.
Vuol bar
davvero causare un comportamento indefinito quando tenta di leggere il numero 0x80
e se è così c'è una soluzione ancora usando un std::istream
?
Edit: Il comportamento non definito mi riferisco al è causato dal istream::read
in buffer
non il cast dal buffer a unsigned char. Ad esempio se è un segno + grandezza macchina e il carattere è firmato allora 0x80 è negativo 0, ma negativo 0 e positivo 0 deve sempre confrontare uguale secondo lo standard. Se questo è il caso, ci sono solo 255 diversi caratteri firmati e non è possibile rappresentare un byte con un carattere. I cast funzioneranno perché aggiungeranno sempre UCHAR_MAX + 1
ai numeri negativi (sezione 4.7 della bozza di C++ 11 standard N3242) quando si esegue il casting con firma non firmata.
"è un comportamento non definito su sistemi in cui il carattere è firmato e non è un complimento di due e non può rappresentare il numero -128" - non del tutto. La conversione da firmata a non firmata è perfettamente definita. Non importa se 'signed char' non può rappresentare' -128' - sarà quindi interpretato come qualunque valore abbia in un'altra rappresentazione (-127 in complemento a 1 o negativo in segno + magnitudine). –
Intendevo che il file può contenere il byte '0x80' e' istream :: read' può leggerlo non la conversione da firmata a non firmata. Ma penso che tu abbia ragione sulla conversione da firmata a non firmata. – qbt937
Sì, può essere letto, come ho accennato qui sotto - tutte e tre le rappresentazioni 'char' firmate hanno una rappresentazione non-trap per il pattern di bit' 10000000'. –