I need to save a float value which is a copied-memory from an integer value.
In reinterpretedFloat
function, I made an sample integer and copy the memory to a float variable.
The thing is the value changes when the memcpy-ed float returns.
Here is the sample code.
#include <stdio.h>
#include <stdint.h>
void printHex(const unsigned char* buff, int count)
{
printf("0X");
for (int i = 0; i < count; ++i)
{
printf("\t%X", buff[i]);
}
printf("\n");
}
float reinterpretedFloat()
{
int32_t value = 0x7F845E58;
float tmp;
memcpy(&tmp, &value, sizeof(float));
printHex(reinterpret_cast<const unsigned char*>(&tmp), 4); //memcpy
return tmp;
}
int main()
{
float newFloat = reinterpretedFloat();
printHex(reinterpret_cast<const unsigned char*>(&newFloat), 4); //returned value
return 0;
}
This is the result.
0X 58 5E 84 7F(memcpy)
0X 58 5E C4 7F(returned value)
What I expected was 0X 58 5E 84 7F
...
Any body can explain why this is happening? In x64 configuration, this does not happens.
0x7f845e58 is a signaling NaN. It gets normalized to 0x7fc45e58, which is a quiet NaN with the same payload.
The difference between x86-64 and 32-bit x86 outcomes is because in the former mode, to return the float
value from reinterpretedFloat()
function, MOVSS
instruction from the SSE ISA extension loads the value into xmm0
register without any conversions, while on the latter, FLD dword [...]
is used, which converts from 32-bit float
to x87's internal 80-bit long double
format, normalizing the signaling status to quiet*.
The difference in mechanism is due to the fact that x86-64 architecture guarantees support for SSE, so the ABI uses it, while i386 ABI doesn't require it, since not all x86 CPUs support it.
* Technically, the conversion causes an Invalid Operation exception, but since it's masked (by default), you get the normalized result of removing signaling status from the NaN