2013-04-03 41 views
4

我有一個通用iOS應用程序,其目標iOS SDK 6.1,編譯器設置爲Apple LLVM編譯器4.2。當我在我的代碼中放置一個斷點並運行以下時,我得到奇怪的結果sin(int)Sin(int)在Xcode調試器(lldb)中損壞

僅供參考,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) 
+0

PO命令打印對象 - 嘗試 'P' 來代替。另外,sin接受弧度參數,所以sin(90)不應該爲零 – Vladimir

+0

@Vladimir:它也發生在p上,我更新了代碼以反映這一點。我知道罪以弧度爲單位,這就是爲什麼第一個輸出是奇怪的。 – Senseful

+1

請給我一個蘋果的錯誤! – matt

回答

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

如果您想爲sin()提供合適原型的lldb,而不必擔心這些問題,那很容易。添加到您的~/.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中評估的每個表達式,它會減慢你的表達如果您將所有原型放入,評估將會停止3210在那裏。

隨着該原型添加到我的target.expr-prefix設置:

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

+1以獲得詳細解釋。儘管我對C一無所知,但它是有道理的。 –

+1

我知道誰會給出答案:-) - 即使我在源文件中包含math.h,lldb也不會「知道」原型嗎?爲什麼如果我在我的項目中定義一個函數'double mysin(double x)',不會發生這個問題?對不起,如果這些是愚蠢的問題:-) –

+0

原型(例如從'')不會因爲空間原因(如果你認爲dSYM今天很大* ...) - 但你自己的功能生成完整的調試信息,因此lldb知道所有參數的類型和返回類型。 –