2009-06-03 110 views
1

我開始調試一些代碼,試圖找到我的錯誤。當我從調試器試圖p tlEntries我得到的由編譯器優化的變量

<variable optimized away by compiler>

消息,而在if聲明停止。下面是我的代碼:

NSArray *tlEntries = [[NSArray alloc] initWithArray:[self fetchJSONValueForURL:url]]; 
for (NSDictionary *info in tlEntries) 
{ 
    if ([info objectForKey:@"screen_name"] != nil) 
     NSLog(@"Found %@ in the timeline", [info objectForKey:@"screen_name"]); 
} 

早些時候調試給了我信心的網址確實是返回一個有效的NSArray,但我不明白爲什麼tlEntries被「優化掉」。

回答

6

編譯器可能注意到你只在開始時使用tlEntries兩次,並且在循環中根本不使用它。如果我沒有記錯的話,循環創建一個枚舉對象,而不是保留對容器對象的引用。所以tlEntries應該對第一行有效,但其餘的都是一樣的。

想法:您可以強制編譯器通過在函數稍後的某處使用tlEntries來保留它。類似於

NSPrint(@"IGNORE THIS LINE %p", tlEntries); 

更好的主意:您可以將優化設置爲-O0。這是強烈建議用於調試代碼。如果使用「調試」而不是「發佈」版本,它應該自動設置爲-O0,但是您可以更改它。

+0

在「爲..在」語法實際上產生一個環路,它相當(一次用於陣列內的每n個元素)上tlEntries調用方法,使從我可以看到編譯器不應該因此而優化它。 – 2009-06-03 23:37:14

17

正確的解決方法是聲明變量以不同的方式如下:

volatile NSArray *tlEntries; 

事實上,volatile關鍵字被用來精確地告知,不得在嘗試優化相關的代碼編譯器以任何方式變化。 親切的問候。

+2

我真的不明白這裏的負面投票。我給出了一個正確的答案,並解決了這個問題(嘗試搜索Objective C文檔或使用google來查找Objective C,C和C++中volatile關鍵字的確切含義)。 – 2009-06-03 06:50:44

1

假設你以後再也不使用這個變量(如果編譯器優化它,似乎是合理的),你可以用一個非常重要的方法來解決這個問題(類似於Dietrich的例子,雖然對你的程序更好)做一個:

[tlEntries release]; 

否則,你一定會泄漏的內存。這將使編譯器看到稍後使用的對象(就像NSPrint一樣),所以它不會被優化。

3

當啓用編譯器優化時,通過將變量放置在寄存器或其他技巧(如語句重新排序)中,變量經常被「優化」。如果您使用除-O0之外的任何-O標誌,則可能發生這種情況。

我不認爲在代碼中添加額外的變量引用將會阻止這種情況發生。 (如果有的話,編譯器可能會更努力,因爲優化它的潛在收益更大。)

作爲臨時解決方法,您可以聲明變量「volatile」。這通常不是一個好的長期解決方案,因爲它會阻止編譯器執行任何涉及該變量的優化。

另一個解決方法是使用良好的老式日誌記錄。例如:

NSLog(@"Entries initialized as: %@", tlEntries); 

最後,您還可以使用-O0進行編譯。許多人推薦使用調試項目配置文件。雖然它阻止了優化,但它使調試變得更容易。逐句通過語句實際上是可預測的,可以查看變量。不幸的是,它有我認爲與蘋果公司的gcc版本相當討厭的副作用:當-O0有效時,你不能在初始化之前得到有關使用變量的警告。 (我個人覺得這個警告很有用,我願意忍受調試的痛苦不太方便。)

P.S.在發佈的代碼段中有內存泄漏;爲了清楚起見,附加的線應添加:

[tlEntries release];