为什么" double"表示为整数?

时间:2016-04-20 17:14:46

标签: c gcc gdb double binary-data

void foo(double a) {  
  ...
}

main()中,我将107.0作为参数传递给foo。然后我使用gdb来检查a的{​​{1}}的二进制表示,这就是我得到的:

p /t a

这个结果对我来说似乎很奇怪。这是INTEGER 107的二进制表示。但是$1 = 1101011 的类型定义为a,我们传递了double的参数。我们知道双精度具有不同的二进制表示形式作为整数。

有谁可以解释为什么107.0有一个整数二进制代表而不是双倍?编译器做了什么有趣的事吗?

4 个答案:

答案 0 :(得分:5)

你告诉gdb把它打印成二进制整数。

 p /t a

如果要查看浮点版本,请使用

 p /f a

Output formats

  

x将值的位作为整数,并打印整数   十六进制。

     

d以带符号的十进制打印为整数。

     

u以无符号十进制形式打印为整数。

     

o以八进制打印为整数。

     

t以二进制形式打印为整数。字母't'代表"两个"。 (2)

     

打印为地址,绝对十六进制和偏移量   从最近的前一个符号。您可以使用此格式   发现未知地址所在的位置(<功能):

     

c作为整数并将其打印为字符常量。

     

f将值的位作为浮点数并打印   使用典型的浮点语法。

     

例如,以十六进制打印程序计数器(参见章节   注册),键入p/x $pc

答案 1 :(得分:1)

双精度以2的幂表示,与整数略有不同。不详细说明,107将是1.101011 *(2 ^ 6)= 1101011.Gdb可能只显示最后的结果,而不是无缘无故地给出完整的64位表示。

答案 2 :(得分:0)

我不熟悉gdb,但是当你写“d”时,它可能会认为你明确表示整数

考虑:

double foo = 1.0;
printf("%d",foo);

c会被混淆,因为你告诉它你会给它一个整数,但你实际上给它一个双倍。

答案 3 :(得分:0)

有几种方法可以打印变量&#39;来自gdb命令行的值。

  • print适用于表达式,并会像C一样进行一些隐式转换。
    您的示例中的p /t a会将“值”转换为整数并将其打印在基数2中。
    您想查看a的位模式,因此print有几个选项:

    • 您可以将其地址转换为指向无符号整数类型的指针,该整数类型的长度与双精度相同 - 在您的示例中可能为unsigned long longuint64_t - 并且取消引用它。
      (gdb) p /t *(uint64_t *)&a
      $6 = 100000001011010110000000000000000000000000000000000000000000000
    • 您可以使用{uint64_t}更简洁地完成同样的事情。
      (gdb) p /t {uint64_t}&a
      $7 = 100000001011010110000000000000000000000000000000000000000000000
  • x显示给定地址的数据,您可以指定数据类型。 /g表示8字节整数。
    (gdb) x /tg &a
    0x7fffffffded8: 0100000001011010110000000000000000000000000000000000000000000000

如果您使用优化,a可能会在注册表中,并且您无法获取其地址,因此上述任何一项都无效。

(gdb) p {uint64_t}&a
Address requested for identifier "a" which is in register $ymm0

gdb支持以各种格式打印AVX寄存器的内容,使用的语法类似于数组的C联合。

(gdb) p $ymm0
$1 = {v8_float = {0, 3.41796875, 0, 0, 0, 0, 0, 0},
v4_double = {107, 0, 0, 0}, v32_int8 = {0, 0, 0, 0, 0, -64, 90, 
64, 0 <repeats 24 times>},
v16_int16 = {0, 0, -16384, 16474, 0 <repeats 12 times>},
v8_int32 = {0, 1079689216, 0, 0, 0, 0, 0, 0},
v4_int64 = {4637229872563879936, 0, 0, 0},
v2_int128 = {0x0000000000000000405ac00000000000, 0x00000000000000000000000000000000}}

(gdb) p /t $ymm0.v4_int64[0]
$2 = 100000001011010110000000000000000000000000000000000000000000000