即使我们将正分数设为双精度型,符号位仍为1的原因

时间:2019-04-14 06:14:24

标签: c

我将正值放入类型为double的变量中。 当我看到内存的内容时,符号位为1。 我认为应该为0,但这可能是错误的。 为什么符号位是1?

#include<stdio.h>

int main(){
    int num=116;

    union {float x; int i;} u4;
    union {double x; long long int i;} u8;

    u4.x = (float) num/10000.0;
    u8.x = (double) num/10000.0;

    printf("%lx\n",u4.i);
    printf("%lx\n",u8.i);

    printf("%.30f\n",u4.x);
    printf("%.30f\n",u8.x);

    return 0;
}

输出:

3c3e0ded
a5119ce0
0.011599999852478504000000000000
0.011599999999999999000000000000

a5119ce0是双精度类型的输出。 a5119ce0表示
1010 0101 0001 0001 1001 1100 1110 0000
它的符号位是1,表示这是负数。

3c3e0ded是浮点类型的输出。 3c3e0ded表示
0011 1100 0011 1110 0000 1101 1110 1101

我也感到困惑的是,使用float和double获得相同长度的结果。

3 个答案:

答案 0 :(得分:3)

如果在打开警告的情况下进行编译,则编译器可能会指出您的错误。例如,使用gcc

$ gcc -Wall main.c 

main.c: In function ‘main’:
main.c:12:12: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
     printf("%lx\n",u4.i);
            ^
main.c:12:12: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
main.c:13:12: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘long long int’ [-Wformat=]
     printf("%lx\n",u8.i);
            ^
main.c:13:12: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘long long int’ [-Wformat=]

进行指示的更正:

printf("%x\n",u4.i);
printf("%llx\n",u8.i);

编译时不显示警告,并产生预期的输出:

3c3e0ded
3f87c1bda5119ce0
0.011599999852478504180908203125
0.011599999999999999200639422270

答案 1 :(得分:2)

您打印错误。记住,C对printf的输入不做任何假设。您要指定%lx来打印双精度字,只有效地打印前32个字节。您应该使用%ll来打印64位整数(在C中称为long long)。

要了解打印的是double的哪32位,还必须了解big-endian和little-endian。基本上,不同的CPU将最低有效位放在首位或最后一位,这意味着根据目标CPU,您将获得最低有效32位或最高有效位。 x86和x64(您可能会在上面运行代码)是小尾数BTW。

答案 2 :(得分:2)

这是您代码的修改版本,以存储在内存中的IEEE-754格式打印浮点值。请注意,大尾数与小尾数的快速而肮脏的测试,这会影响我们的打印方式:

int main()
{
    unsigned int test = 0x01020304;
    int isBigEndian = (1 == *(char*)&test);
    float num = 3.14;

    // breaking the rules here, but this will work for demonstration purposes
    unsigned char* ptr = (unsigned char*)&num

    // we're assuming sizeof(float) == 4
    if (isBigEndian)
        printf("0x%02x%02x%02x%02x\n", ptr[0], ptr[1], ptr[2], ptr[3]);
    else
        printf("0x%02x%02x%02x%02x\n", ptr[3], ptr[2], ptr[1], ptr[0]);

    return 0;

}