void foo(double a) {
...
}
在main()
中,我将107.0
作为参数传递给foo
。然后我使用gdb来检查a
的{{1}}的二进制表示,这就是我得到的:
p /t a
这个结果对我来说似乎很奇怪。这是INTEGER 107的二进制表示。但是$1 = 1101011
的类型定义为a
,我们传递了double
的参数。我们知道双精度具有不同的二进制表示形式作为整数。
有谁可以解释为什么107.0
有一个整数二进制代表而不是双倍?编译器做了什么有趣的事吗?
答案 0 :(得分:5)
你告诉gdb把它打印成二进制整数。
p /t a
如果要查看浮点版本,请使用
p /f a
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 long
或uint64_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