memcpy non sta facendo come dovrebbe
Domanda
Ho questo bit di codice che sta producendo risultati sbagliati.
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char bytes[4];
float flt=0;
bytes[0]=0xde;
bytes[1]=0xad;
bytes[2]=0xbe;
bytes[3]=0xef;
memcpy( &flt, bytes, 4);
printf("bytes 0x%x float %e\n", flt, flt);
return 0;
}
l'output che ottengo è
byte 0xc0000000 float -2.000001e + 00
Mi aspetto di ottenere
byte 0xdeadbeef float -6.2598534e + 18
modifica n. 1 come è stato sottolineato, l'endianità potrebbe essere diversa e ciò comporterebbe il seguente
byte 0xefbeadde float -1.1802469e + 29
quello che non capisco è il cast da float a unsigned int che risulta in 0xc0000000 (il float nella stessa istruzione printf è -2.0000 che attribuirei all'ottimizzazione del compilatore)
prima funzionava su un altro computer. Potrebbe essere un cambiamento di architettura.
Soluzione
Non è un problema di memcpy.
-
float
viene sempre convertito indouble
quando viene passato su...
di printf, quindi non è possibile ottenere 4 byte sulla maggior parte delle architetture Intel. - quando ti aspetti
0xdeadbeef
in questo codice, supponi che la tua architettura sia BIG endian. Esistono molte piccole architetture endian, ad esempio Intel x86.
Altri suggerimenti
Ti rendi conto che i float sono promossi a raddoppiare quando passati a una variabile parametri funzionano come printf ()? Quindi quando dici:
printf("bytes 0x%x float %e\n", flt, flt);
stai provando a trattare quelli che in realtà sono due valori a 8 byte come due 4 byte valori, dando (credo) un comportamento indefinito.
Il "% x " in printf prevede un int senza segno. Gli stai dando un float che viene convertito automaticamente e non è quello che vuoi. Vuoi fare qualcosa del tipo:
printf("bytes 0x%x float %e\n", *((unsigned int *)&flt), flt);
Oh, e come ha sottolineato qualcun altro, se sei su x86 non vedrai 0xdeadbeef, più come 0xefbeadde.
Vedi se è meglio:
printf("bytes 0x%x float %e\n", *(int *)&flt, flt);
Per vedere la promozione dei parametri, cambia la dichiarazione da float a double. Sulla mia macchina, che stampa:
bytes 0xefbeadde float -1.860545e+230
0xefbeadde è big-endian per deadbeaf. Gli ultimi 4 byte del doppio non sono definiti, quindi il numero visualizzato dopo il float varierà.
Hai detto che funzionava su un altro computer, che tipo di computer era? Deve essere stato un piccolo endian dove sizeof (float) == sizeof (double) :)