Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reinterpret int32 to float

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.

like image 655
JaeJun LEE Avatar asked May 28 '18 16:05

JaeJun LEE


People also ask

Is Int32 a float?

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).

What is reinterpret_ cast in c++?

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.

Is reinterpret_ cast compile time?

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.


1 Answers

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

like image 91
Ruslan Avatar answered Oct 09 '22 22:10

Ruslan