【问题标题】:Why is "double" represented as integer?为什么“双”表示为整数?
【发布时间】:2016-04-20 17:14:45
【问题描述】:
void foo(double a) {  
  ...
}

main() 中,我将107.0 作为其参数传递给foo。然后我用 gdb 检查了p /t aa 的二进制表示,这就是我得到的:

$1 = 1101011

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

谁能解释为什么a 有一个整数二进制代表而不是双精度?编译器有什么好笑的吗?

【问题讨论】:

  • /t 并不意味着打印位模式,它只是表示值的基数 2 表示,值本身是 107(gdb 知道您的 a 的类型)。要找出位模式,请使用x 命令。

标签: c gcc gdb double binary-data


【解决方案1】:

您告诉 gdb 将其打印为二进制整数。

 p /t a

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

 p /f a

Output formats

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

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

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

o 打印为八进制整数。

t 以二进制整数形式打印。字母“t”代表“二”。 (2)

a 打印为地址,无论是十六进制的绝对地址还是偏移量 从最近的前面的符号。您可以使用这种格式用于 发现未知地址的位置(在什么函数中):

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

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

例如,以十六进制打印程序计数器(请参阅第 寄存器),输入p/x $pc

【讨论】:

  • 抱歉打错了。我实际上使用的是p /t a。但无论如何,格式说明符是\t,它告诉它以二进制形式打印。所以原来的错字d 只作为变量名。
  • @OneZero 网页说它应该是一个正斜杠 例如,要以十六进制打印程序计数器(参见寄存器部分),请键入 p/x $pc
【解决方案2】:

双数以 2 的幂表示,与整数略有不同。没有太多细节,107 将是 1.101011 * (2^6) = 1101011。gdb 可能只显示最后一个结果,而不是无缘无故地给你完整的 64 位表示。

【讨论】:

    【解决方案3】:

    有几种方法可以从 gdb 命令行打印变量的值。

    • print 作用于表达式,并且会进行一些隐式转换,就像 C 一样。
      p /t a 在您的示例中会将 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
    

    【讨论】:

      【解决方案4】:

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

      考虑:

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

      c 会感到困惑,因为你告诉它你会给它一个整数,但实际上你给它的是一个双精度数。

      【讨论】:

        猜你喜欢
        • 2017-12-15
        • 1970-01-01
        • 2012-11-04
        • 2017-01-10
        • 2016-02-18
        • 2015-03-12
        • 2012-08-20
        • 1970-01-01
        • 2021-02-04
        相关资源
        最近更新 更多