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.
Is it Int32 or Single? Single precision, usually used to represent the “float” type in the C language family (though this is not guaranteed). This is a binary format that occupies 32 bits (4 bytes) and its significand has a precision of 24 bits (about 7 decimal digits).
reinterpret_cast is a type of casting operator used in C++. It is used to convert a pointer of some data type into a pointer of another data type, even if the data types before and after conversion are different. It does not check if the pointer type and data pointed by the pointer is same or not.
It is purely a compile-time directive which instructs the compiler to treat expression as if it had the type new-type. Only the following conversions can be done with reinterpret_cast, except when such conversions would cast away constness or volatility.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With