以字节方式打印双倍值正在反转实际值

时间:2015-11-03 22:46:22

标签: c double unions

请找到我的示例代码,以说明我的问题:

#include<stdio.h>
typedef struct {
    char b[8];
} byte_wise_double_t;

typedef union {
    byte_wise_double_t bwd;
    double val;
} DOUBLE_T;

int main() {
    double tmp;
    int ii;
    DOUBLE_T my_val;

    printf("Enter a value:\n");
    scanf("%lf", &tmp);
    printf("The read number is: %e\n", tmp);
    my_val.val = tmp;
    printf("Printing the value bytewise:\n");
    for (ii=0; ii<8; ii++) {
        printf("%02x", (my_val.bwd.b[ii] & 0xff));
    }

    printf("\nReverse printing the value bytewise:\n");
    for (ii=7; ii>=0; ii--) {
        printf("%02x", (my_val.bwd.b[ii] & 0xff));
    }
    return 0;
}

当您输入浮动值时,我按字节顺序打印双值,首先按预期的正确顺序打印,然后按相反顺序打印。但事实证明,第二个print语句给出了输入double的正确十六进制表示。这是一个示例输出:

Enter a value:
11.23456
The read number is: 1.123456e+001
Printing the value bytewise:
47e6913f18782640
Reverse printing the value bytewise:
402678183f91e647

请解释为什么会这样。

2 个答案:

答案 0 :(得分:3)

我认为这是一个小端与大端的误解。

为简单起见,请查看16位整数。让我们说0xaa55(十进制43605)。

默认情况下,此数字与低位插槽中的低位字节和高位插槽中的高位字节一起存储。

16-bit: 0xaa55

8-bit: byte[1] = 0xaa, byte[0] = 0x55;

您的第一个声明是从右到左打印十六进制,第二个声明是从左到右打印十六进制(当您阅读时)。看看我的小整数示例,你的第一个for循环将打印'55'然后'aa',反转低和高字节。第二个循环打印从高字节到低字节的数字,就像你读它一样。

答案 1 :(得分:1)

您可能正在英特尔处理器上运行此代码。此处理器以 little-endian 顺序将值存储在内存中,其中字节从最低有效字节开始存储。因此,例如,32位整数0xdeadbeef作为&#34; EF BE AD DE&#34;存储在存储器中。这也扩展到64位整数和双精度,这解释了你所看到的逆转。

如果您想按照预期的方式打印double的十六进制值,请将其与uint64_t联合起来:

typedef union {
    uint64_t intval;
    double dblval;
} DOUBLE_T;

...

DOUBLE_T my_val;
my_val.dblval = 1.2345;
printf("%016llx\n", my_val.intval);

(注意:这不是可移植代码:它假设您可以使用doubleuint64_t添加别名,但在所有系统上都不是。但是,它应该适用于GCC, Clang,或典型英特尔处理器上的MSVC。)