2010-06-16 56 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宏!