显示双倍十六进制的位模式?

时间:2018-11-07 06:14:55

标签: c++ c floating-point double type-punning

我正在尝试使用printf来将double的二进制表示形式打印到控制台上。这是我到目前为止的代码:

#include <stdio.h>

int main()
{
    double a = 4.75;
    unsigned long long b = *(unsigned long long *) &a;
    printf("Double a = %f (0x%x)" a, b);
}

我还尝试将其从很长很长的时间更改为很长的时间。这是我在gcc linux中执行此操作的结果:

Double a = 4.750000 (0x0)

我很确定,因为我的系统是低端字节序的,所以它只捕获所有为零的前32位。但是,我不确定如何解决此问题。

我认为可能是因为linux中long是64位,但是经过测试,我再次得到了相同的结果。也许我打印不正确?不确定,请告诉我,谢谢您的时间。

3 个答案:

答案 0 :(得分:3)

在C语言中,类似

unsigned long long b = *(unsigned long long *) &a;

是非法的,因为它违反了一种称为严格别名的规则,该规则涉及一种引用不同类型对象的一种类型的指针。

但是,有一个例外: char指针可以为任何对象起别名

因此,使用char指针,您可以在C语言中执行以下操作:

#include <stdio.h>

int main()
{
    double a = 4.75;
    unsigned char* p;

    // Method 1 - direct memory read
    p = (unsigned char*)&a;
    for (size_t i=0; i < sizeof(double); ++i)
    {
        printf("%02x ", *p);
        ++p;
    }
    printf("\n");

    // Method 2 - reversed memory read
    size_t i = sizeof(double);
    p = (unsigned char*)&a + i - 1;
    do
    {
        printf("%02x ", *p);
        --p;
        --i;
    } while(i > 0);

    return 0;
}

输出:

00 00 00 00 00 00 13 40 
40 13 00 00 00 00 00 00

这两种方法以不同的字节序打印。

如果您不喜欢指针,则可以选择使用联合。喜欢:

#include <stdio.h>

int main()
{
    union
    {
        double a;
        char c[sizeof(double)];
    } d;
    d.a = 4.75;

    for (size_t i=0; i < sizeof(double); ++i)
    {
        printf("%02x ", d.c[i]);
    }
    printf("\n");

    size_t i = sizeof(double);
    do
    {
        --i;
        printf("%02x ", d.c[i]);
    }
    while (i > 0);
    printf("\n");


    return 0;
}

输出:

00 00 00 00 00 00 13 40 
40 13 00 00 00 00 00 00 

答案 1 :(得分:3)

您的代码有两个问题,一个简单的问题是您使用了错误的格式说明符%llx unsigned long long 的正确说明符。 clang和gcc都使用-Wallsee it live对此提供了警告。

第二个问题是您在这里违反了strict aliasing rule

unsigned long long b = *(unsigned long long *) &a;

(在C和C ++中)键入Pun的正确方法是使用memcpy(see it working live):

std::memcpy( &b, &a, sizeof(double));

在上述C ++ 20中的严格别名链接中,我们应该获得bit_cast,它将简化类型化对等操作,例如:

b = bit_cast<unsigned long long>(a);

答案 2 :(得分:2)

在C ++中:

double a = 4.75;
char tmp[sizeof(double)];
memcpy(tmp, &a, sizeof(double));
... // print individual bytes as hex

或者:

double a = 4.75;
unsigned char* tmp = reinterpret_cast<unsigned char*>(&a);
for (int i = 0; i < sizeof(double); i++)
  ... // print *(tmp + i) as hex