在Xcode调试器(lldb)中断了Sin(int)

时间:2013-04-03 16:29:23

标签: xcode debugging lldb

我有一个针对iOS SDK 6.1的通用iOS应用,并且编译器设置为 Apple LLVM编译器4.2 。当我在我的代码中放置一个断点并运行以下内容时,我得到sin(int)的奇怪结果。

供参考,sin(70) = 0.7739(70以弧度表示)。

(lldb) p (double)sin(70)
(double) $0 = -0.912706376367676 // initial value
(lldb) p (double)sin(1.0)
(double) $1 = 0.841470984807897 // reset the value sin(int) will return
(lldb) p (double)sin(70)
(double) $2 = 0.841470984807905 // returned same as sin(1.0)
(lldb) p (double)sin(70.0)
(double) $3 = 0.773890681557889 // reset the value sin(int) will return
(lldb) p (double)sin(70)
(double) $4 = 0.773890681558519
(lldb) p (double)sin((float)60)
(double) $5 = -0.304810621102217 // casting works the same as appending a ".0"
(lldb) p (double)sin(70)
(double) $6 = -0.30481062110269
(lldb) p (double)sin(1) 
(double) $7 = -0.304810621102223 // every sin(int) behaves the same way

观察:

  • 调试会话中sin(int)的第一个值始终为-0.912706376367676
  • sin(int)将始终返回上次执行的sin(float)返回的相同值。
  • 如果我将p替换为poexpr(例如expr(double)sin(70)),我会得到相同的结果。

为什么调试器的行为如此?

这是否意味着每次调用函数时都应该输入每个参数?

NSLog的一些更有趣的行为:

(lldb) expr (void)NSLog(@"%f", (float)sin(70))
0.000000 // new initial value
(lldb) expr (void)NSLog(@"%f", (float)sin(70.0))
0.773891
(lldb) expr (void)NSLog(@"%f", (float)sin(70))
0.000000 // does not return the previous sin(float) value
(lldb) p (double)sin(70)
(double) $0 = 1.48539705402154e-312 // sin(int) affected by sin(float) differently
(lldb) p (double)sin(70.0)
(double) $1 = 0.773890681557889
(lldb) expr (void)NSLog(@"%f", (float)sin(70))
0.000000 // not affected by sin(float)

1 个答案:

答案 0 :(得分:4)

你正在进入C中默认参数促销的精彩世界。请记住,lldb不知道sin()的参数类型或返回类型是什么。正确的原型是double sin (double)。当你写

(lldb) p (float) sin(70)

这有两个问题。首先,您提供了一个整数参数,C默认促销规则将把它作为int传递给所讨论的体系结构上的4字节值。除了8字节之外,double是完全不同的编码。所以sin正在获取垃圾输入。其次,sin()在这些体系结构上返回double或8字节值,但是你告诉lldb要抓取它的4个字节并做一些有意义的事情。如果您调用p (float)sin((double)70)(因此只有返回类型不正确),lldb将打印一个无意义的值,如9.40965e + 21而不是0.773891。

当你写

(lldb) p (double) sin(70.0)
你修正了这些错误。浮点类型的默认C提升是将其作为double传递。如果您致电sinf(),则会遇到问题,因为该功能只需要float

如果你想为lldb提供sin()的正确原型并且不担心这些问题,那就很容易了。将其添加到您的~/.lldbinit文件

settings set target.expr-prefix ~/lldb/prefix.h

(我有一个~/lldb目录,我存储有用的python文件和类似的东西)和~/lldb/prefix.h将会读取

extern "C" {
int strcmp (const char *, const char *);
void printf (const char *, ...);
double sin(double);
}

(你可以看到我的前缀文件中也有strcmp()printf()的原型,所以我不需要这些原型。)你不想放太多东西这里 - 这个文件被预先添加到你在lldb中评估的每个表达式中,如果你将所有原型放在/usr/include中,它将减慢你的表达式评估。

将该原型添加到我的target.expr-prefix设置中:

(lldb) p sin(70)
(double) $0 = 0.773890681557889