在许多C/C++宏中,我看到宏的代码包含在看似无意义的do while循环中.这是一些例子.
#define FOO(X) do { f(X); g(X); } while (0)
#define FOO(X) if (1) { f(X); g(X); } else
Run Code Online (Sandbox Code Playgroud)
我看不出它do while在做什么.为什么不在没有它的情况下写这个?
#define FOO(X) f(X); g(X)
Run Code Online (Sandbox Code Playgroud) 我们可以写一个if声明
if (a == 5, b == 6, ... , thisMustBeTrue)
Run Code Online (Sandbox Code Playgroud)
只有最后一个条件才能进入if身体.
为什么允许?
这个问题不受任何特定编译器警告的约束,以下只是一个例子.
目前我想要一个检查内部退出条件的循环:
while( true ) {
doSomething();
if( condition() ) {
break;
}
doSomethingElse();
}
Run Code Online (Sandbox Code Playgroud)
我不能在Visual C++中编写它 - 它会发出C4127 conditional expression is constant警告.编译器会在我脸上挥动它,虽然很明显它while(true)不能被意外地写出来.
假设我想要编译而没有警告的代码.我的服务有各种解决方法.
解决方法是使用for(;;)但感觉很愚蠢 - 为什么我想要那个奇怪的东西而不是简洁优雅的惯用语while(true)?解决方法二是在行#pragma warning( suppress)之前使用,while( true )但它添加了一个巨大的横幅,它是while-statement本身的两倍.解决方法三是为整个项目禁用C4127(我已经看到它在一个真实项目中完成)但是所有可能的C4127实例也被禁用.
是否有任何优雅的方法来摆脱毫无意义的警告?
一位客户最近对我雇主的C代码库进行了静态分析,并向我们提供了结果.有用的补丁包括将着名do { ... } while(0)宏更改为的请求do { ... } while(0,0).我理解他们的补丁正在做什么(使用序列运算符将evaluate 返回到第二个"0"的值,因此效果是相同的)但是不清楚他们为什么喜欢第二种形式而不是第一种形式.
有没有合理的理由为什么人们应该更喜欢第二种形式的宏观,还是我们客户的静态分析过于迂腐?
//file error.h
#define FAIL(message) \
do { \
std::ostringstream ossMsg; \
ossMsg << message; \
THROW_EXCEPTION(ossMsg.str());\
} while (false)
//main.cpp
...
FAIL("invalid parameters"); // <<< warning C4127: conditional expression is constant
...
Run Code Online (Sandbox Code Playgroud)
如您所见,警告与该警告有关do {} while(false).
我只能想出以下方法来禁用警告:
#pragma warning( push )
#pragma warning( disable : 4127 )
FAIL("invalid parameters");
#pragma warning( pop )
Run Code Online (Sandbox Code Playgroud)
但我不喜欢这个解决方案.
我也尝试将这些宏放在error.h中而没有效果.
有关如何以体面的方式抑制此警告的任何评论?
谢谢
在关于无限循环的编码风格问题中,有些人提到他们更喜欢for(;;)样式,因为while(true)样式在MSVC上给出关于条件表达式是常量的警告消息.
这让我感到非常惊讶,因为在条件表达式中使用常量值是避免#ifdef地狱的有用方法.例如,您可以在标题中:
#ifdef CONFIG_FOO
extern int foo_enabled;
#else
#define foo_enabled 0
#endif
Run Code Online (Sandbox Code Playgroud)
代码可以简单地使用条件并信任编译器在未定义CONFIG_FOO时删除死代码:
if (foo_enabled) {
...
}
Run Code Online (Sandbox Code Playgroud)
每次使用foo_enabled时,不必测试CONFIG_FOO:
#ifdef CONFIG_FOO
if (foo_enabled) {
...
}
#endif
Run Code Online (Sandbox Code Playgroud)
这种设计模式一直在Linux内核中使用(例如,include/linux/cpumask.h在禁用SMP时将几个宏定义为1或0,在启用SMP时定义为函数调用).
MSVC警告的原因是什么?另外,有没有更好的方法来避免#ifdef hell而不必禁用该警告?或者这是一个过于广泛的警告,一般不应该启用?