barej
barej

Reputation: 1406

Inline assembly inside C++ for data conversion

I am trying to write a C++ code for conversion of assembly dq 3FA999999999999Ah into C++ double. What to type inside asm block? I dont know how to take out the value.

int main()
{
    double x;

    asm
    {
        dq  3FA999999999999Ah
        mov x,?????
    }

    std::cout<<x<<std::endl;

    return 0;
}

Upvotes: 0

Views: 208

Answers (1)

shuttle87
shuttle87

Reputation: 15934

From the comments it sounds a lot like you want to use a reinterpret cast here. Essentially what this does is to tell the compiler to treat the sequence of bits as if it were of the type that it was casted to but it doesn't do any attempt to convert the value.

uint64_t raw = 0x3FA999999999999A;
double x = reinterpret_cast<double&>(raw);

See this in action here: http://coliru.stacked-crooked.com/a/37aec366eabf1da7

Note that I've used the specific 64bit integer type here to make sure the bit representation required matches that of the 64bit double. Also the cast has to be to double& because of the C++ rules forbidding the plain cast to double. This is because reinterpret cast deals with memory and not type conversions, for more details see this question: Why doesn't this reinterpret_cast compile?. Additionally you need to be sure that the representation of the 64 bit unsigned here will match up with the bit reinterpretation of the double for this to work properly.

EDIT: Something worth noting is that the compiler warns about this breaking strict aliasing rules. The quick summary is that more than one value refers to the same place in memory now and the compiler might not be able to tell which variables are changed if the change occurs via the other way it can be accessed. In general you don't want to ignore this, I'd highly recommend reading the following article on strict aliasing to get to know why this is an issue. So while the intent of the code might be a little less clear you might find a better solution is to use memcpy to avoid the aliasing problems:

#include <iostream>

int main()
{
    double x;
    const uint64_t raw = 0x3FA999999999999A;
    std::memcpy(&x, &raw, sizeof raw); 
    std::cout<<x<<std::endl;

    return 0;
}

See this in action here: http://coliru.stacked-crooked.com/a/5b738874e83e896a

This avoids the issue with the aliasing issue because x is now a double with the correct constituent bits but because of the memcpy usage it is not at the same memory location as the original 64 bit int that was used to represent the bit pattern needed to create it. Because memcpy is treating the variable as if it were an array of char you still need to make sure you get any endianness considerations correct.

Upvotes: 2

Related Questions