Sin(int)在Xcode调试器(lldb)中被破坏 [英] Sin(int) is broken in Xcode debugger (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 //初始值
(lldb)p (double)sin(1.0)
(double)$ 1 = 0.841470984807897 //重置值sin(int)将返回
(lldb)p(double)sin(70)
(double) $ 2 = 0.841470984807905 //返回与sin(1.0)相同
(lldb)p(double)sin(70.0)
(double)$ 3 = 0.773890681557889 //重置值sin(int)将返回
(lldb)p(double)sin(70)
(double)$ 4 = 0.773890681558519
(lldb)p(double)sin((float)60)
(double)$ 5 = -0.304810621102217 //铸造工作与添加.0相同
(lldb)p(double)sin(70)
(double)$ 6 = -0.30481062110269
(lldb)p double)sin(1)
(double)$ 7 = -0.304810621102223 //每个sin(int)的行为方式与
观察:
-
sin int)
在调试会话中总是-0.912706376367676
。 -
sin int)
将始终返回从最后执行的sin(float)
返回的相同值。 - 如果我用
po
或expr
替换p
(例如expr(double)sin(70)),我得到相同的确切结果。
为什么调试器的行为是这样的? p>
这是否意味着我每次调用函数时都应该输入每个参数的值?
一些更有趣的行为使用NSLog:
(lldb)expr(void)NSLog(@%f,(float)sin(70))
0.000000 //新初始值
(lldb)expr(void)NSLog(@%f,(float)sin(70.0))
0.773891
(lldb)expr (void)NSLog(@%f,(float)sin(70))
0.000000 //不返回先前的sin(float)值
(lldb)p(double) )
(double)$ 0 = 1.48539705402154e-312 //受sin(float)影响的sin(int)不同的
(lldb)p(double)sin(70.0)
(double)$ 1 = 0.773890681557889
(lldb)expr(void)NSLog(@%f,(float)sin(70))
0.000000 //不受sin(float)影响
你正在走进美妙的默认参数pr记住,记住,lldb不知道 sin()
的参数类型或返回类型是什么。正确的原型是 double sin(double)
。当你写
(lldb)p(float)sin(70)
/ pre>
有两个问题。首先,您提供一个整数参数,C默认升级规则将作为一个
int
传递,相关架构上的4字节值。double
除了是8个字节,是完全不同的编码。所以sin
正在获得垃圾输入。第二,sin()
在这些体系结构上返回一个double
或8个字节,但是你告诉lldb抓住4个字节,做一些有意义的事情。如果你调用了p(float)sin((double)70)
(所以只有返回类型不正确)lldb会打印一个无意义的值,如9.40965e + 21的0.773891。
当你写了
(lldb)p双)sin(70.0)
你修复了这些错误。浮点类型的默认C升级是将其作为
double
传递。如果你正在调用sinf()
,那么你会遇到问题,因为这个函数只有一个float
。
如果你想为
sin()
提供一个正确的原型,而不用担心这些问题,这很容易。将其添加到您的〜/ .lldbinit
文件,设置设置目标.expr-prefix〜/ lldb / prefix.h
(我有一个
〜/ lldb
目录,我存储有用的python文件和这样的东西)和〜/ lldb / prefix.h
将读取externC{
int strcmp(const char *,const char *);
void printf(const char *,...);
双罪(双);
}
(你可以看到我也有
我的前缀文件中的strcmp()
和printf()
,所以我不需要投这些。)你也不想放很多东西在这里 - 这个文件是在lldb中评估的每一个表达式的前提下,如果把所有原型放在/ usr / include
中
将原型添加到我的
target.expr-prefix
设置:(lldb)p sin(70)
(double)$ 0 = 0.773890681557889
I have an universal iOS app targeting iOS SDK 6.1, and the compiler is set to Apple LLVM compiler 4.2. When I place a breakpoint in my code and run the following I get weird results for
sin(int)
.For reference,
sin(70)
=0.7739
(70 is in radians).(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
Observations:
- The first value for
sin(int)
in a debug session is always-0.912706376367676
. sin(int)
will always return the same value that was returned from the last executedsin(float)
.- If I replace
p
withpo
, orexpr
(e.g. expr (double)sin(70)), I get the same exact results.
Why is the debugger behaving like this?
Does this mean that I should type cast every single parameter each time I call a function?
Some more interesting behavior with 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)
You're walking into the wonderful world of default argument promotions in C. Remember, lldb doesn't know what the argument types or return type of sin()
is. The correct prototype is double sin (double)
. When you write
(lldb) p (float) sin(70)
there are two problems with this. First, you're providing an integer argument and the C default promotion rules are going to pass this as an int
, a 4-byte value on the architectures in question. double
, besides being 8-bytes, is an entirely different encoding. So sin
is getting garbage input. Second, sin()
returns a double
, or 8-byte on these architectures, value but you're telling lldb to grab 4 bytes of it and do something meaningful. If you'd called p (float)sin((double)70)
(so only the return type was incorrect) lldb would print a nonsensical value like 9.40965e+21 instead of 0.773891.
When you wrote
(lldb) p (double) sin(70.0)
you fixed these mistakes. The default C promotion for a floating point type is to pass it as a double
. If you were calling sinf()
, you'd have problems because the function expected only a float
.
If you want to provide lldb with a proper prototype for sin()
and not worry about these issues, it is easy. Add this to your ~/.lldbinit
file,
settings set target.expr-prefix ~/lldb/prefix.h
(I have a ~/lldb
directory where I store useful python files and things like this) and ~/lldb/prefix.h
will read
extern "C" {
int strcmp (const char *, const char *);
void printf (const char *, ...);
double sin(double);
}
(you can see that I also have prototypes for strcmp()
and printf()
in my prefix file so I don't need to cast these.) You don't want to put too many things in here - this file is prepended to every expression you evaluate in lldb and it will slow your expression evaluations down if you put all the prototypes in /usr/include
in there.
With that prototype added to my target.expr-prefix
setting:
(lldb) p sin(70)
(double) $0 = 0.773890681557889
这篇关于Sin(int)在Xcode调试器(lldb)中被破坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!