2

这是我对NSLog()智能变体的搜索。 BetterLog()的一个关键特性是NSLog()替代版本无法用于发布和分发版本。所提出的解决方案(参见例如Is it true that one should not use NSLog() on production code?)定义了预处理器符号,以根据构建类型来控制BetterLog()的定义。通常为:如何通过有条件编译的NSLog替换避免“未使用的变量”编译器警告?

#ifdef DEBUG_MODE 
    #define DebugLog(s, ...) NSLog(@"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__]) 
#else 
    #define DebugLog(s, ...) 
#endif 

其中DEBUG_MODE将被定义为仅用于调试生成一个预处理器符号。

但是,在很多情况下,即当记录语句使用中间变量构建时,结果是未使用变量的编译器警告。这里是一个例子:

if (error) { 
    NSString *titleString = @"Error downloading thumbnail, will rebuild it"; 
    NSString *messageString = [error localizedDescription]; 
    NSString *moreString = [error localizedFailureReason] ? [error localizedFailureReason] : NSLocalizedString(@"Check the URL.", nil); 
    BetterLog(@"%@: %@. %@", titleString, messageString, moreString); 
} // silently ignoring *this* error is OK. 

这里所有三个字符串都会产生编译器警告。我讨厌编译器警告。

当然,不可能避免没有条件地包括变量声明本身。我做了以下尝试,但它不起作用:

而不是简单地在调试模式下定义DEBUG_MODE,我总是定义它,值为1在调试模式下,值为0在释放模式下。

然后我试图利用编译器死代码剥离优化:

if (DEBUG_MODE && error) { 
    // snip 
} 

的代码是确定:它是正确的释放模式剥离出来。然而,编译器仍然会发出未使用的变量警告。

所以,问题是:是不是可以做多难看更好:

#if DEBUG_MODE 
if (error) { 
    // snip 
} 
#endif 

回答

1

一种选择是:

#define BetterLog(...) do { (void)(__VA_ARGS__); } while (0) 

这样做的好处是,如果你达到一个BetterLog()中,它的参数的任何副作用都将被评估,并且它是一个干净的语句,所以编写if (x) BetterLog(@"%@", x);(这会破坏使用宏的下一个语句)并不是一个错误。

就个人而言,我更喜欢使用“丑陋的”预处理器方法,因为它明确指出排除调试代码。

+0

什么是'while(0)' – 2010-09-15 02:45:01

+0

Alexsander,请参阅C FAQ的问题10.4:http://c-faq.com/cpp/multistmt.html(错误:关于“非标准” inline'关键字已经过时了,因为它在11年前被标准化了。) – 2010-09-15 13:51:02

+0

只有当传入1个参数时才有效,一旦两个参数传入,我仍然会收到警告 – 2013-09-05 14:56:38