2010-06-16 49 views
3

我使用一些Qt代碼,增加了一個VERIFY宏,看起來是這樣的:轉換宏到內聯函數

#define VERIFY(cond) \ 
{ \ 
    bool ok = cond; \ 
    Q_ASSERT(ok); \ 
} 

然後,該代碼可以使用它同時又是某些病情反而評估,如:

Q_ASSERT(callSomeFunction()); // callSomeFunction not evaluated in release builds! 
VERIFY(callSomeFunction()); // callSomeFunction is always evaluated 

不喜歡宏,我反而喜歡把它變成一個內聯函數:

inline VERIFY(bool condition) 
{ 
    Q_ASSERT(condition); 
} 

但是,在發佈版本中,我擔心編譯器會優化所有對此函數的調用(因爲Q_ASSERT實際上不會做任何事情)。我是不必要地擔心或者這可能取決於優化標誌/編譯器/等。?我想我可以改變它:

inline VERIFY(bool condition) 
{ 
    condition; 
    Q_ASSERT(condition); 
} 

但是,再次,編譯器可能是聰明的,可以忽略該調用。

對於調試版本和發佈版本,這種內聯方案是否安全?

回答

2

在內聯函數的情況下,不保證函數參數不被評估。

由於他們的評估可能有或沒有副作用,所以您最好在艱難的時候維護代碼 - 在有副作用的情況下肯定會發生評估,在其他情況下會發生或不發生由編譯器自行決定。這會給你留下一個程序,其行爲以鬆散控制的方式進行。

所以,即使你對宏不喜歡,你也應該做出明智的決定。要麼使用宏,然後整個構造被預處理器消除,參數不被評估,或者使用內聯函數,然後編譯器爲您做出決定。

+0

我決定不承擔風險。謝謝! – Rob 2010-06-16 20:36:12

4

即使編譯器優化了內聯VERIFY函數,那麼這並不意味着它不會調用生成bool參數的函數。

Q_ASSERT沒有調用在發佈版本中傳遞給它的函數的原因是它是一個宏,它根本不會替代函數調用,所以沒有什麼可以優化的。

0

優化器不會刪除有副作用的代碼,否則優化程序會改變它的工作方式!在這種情況下,如果函數參數具有副作用(例如將某些東西打印到控制檯),則函數參數將始終被評估,即使傳遞給它的函數完全被消除。

想象這樣的代碼:

int x = Return5(); 
int y = PrintToConsoleAndReturn5(); 

// x and y never used again 

優化器可以省略調用Return5()(假定它由簡單地return 5;),因爲它沒有副作用,因此整個線將發射任何操作。但是,優化器不能省略對PrintToConsoleAndReturn5()的調用(但可能會內聯),因爲它有副作用。它可以省略返回整數5並將其存儲到y,因爲該代碼沒有副作用。總之,理論是程序的行爲應該是相同的,無論是優化的還是非優化的,所以你應該在你的原始問題中確定。

0

優化期間,編譯器仍然必須尊重手頭的代碼的可觀察到的影響。這意味着它必須保持callSomeFunction()如果調用是可觀察的。 (有一些特定的例外情況適用於複製周圍的對象,在這裏可以注意到刪除副本 - 這裏無關)。

然而,優化不會在釋放模式的重要Q_ASSERT(callSomeFunction());。當預處理器完成時,沒有什麼可以優化的,並且擴展了Q_ASSERT宏!