我在“发布”中使用下面的代码断言,有一段时间没有任何问题。 然后是Visual Studio 2010 Pro SP1,事情向南,as also happened to mr. Krunthar。
问题是,当我有一段代码时,我会像这样进行健全性检查:
#define ASSERT(condition, msg) do { (void)sizeof(condition); } while (0,0)
// Note: (0,0) is to avoid warning C4127: conditional expression is constant
{
int result = CallMeOnce(); // its side effects are the important stuff
// perform additional sanity checks in debug
ASSERT(result >= 0, "too low");
ASSERT(result <= 100, "too high");
ASSERT(!isPrime(result), "too prime");
}
VS2010吐出warning C4189: 'result' : local variable is initialized but not referenced
我对如何解决这个问题感到茫然:
(void)(condition)
这样的代码将执行作为条件传递的任何表达式,这是一个否定的CallMeOnce()
置于ASSERT表达式中是不可能的CallMeOnce()
不是一个选项(void)result
,if (result == result) {}
或UNREFERENCED_PARAMETER(result)
(或等效)这样的脚手架代码,只是为了避免警告,因为它会使代码变得更难阅读(污染),在Debug中编写代码时很容易忘记。还有:在很多地方!我正在考虑为变量创建另一个宏(ASSERTU?),但感觉如此......古怪! 有没有人找到更好的出路?
非常感谢!
编辑:明确了调用者级别变量处理的首选项
答案 0 :(得分:0)
在您的断言宏中
(void)sizeof(condition);
大概这个代码是由其他人编写的,所以,解释:
(void)
强制转换的rôle是告诉编译器你真的打算把这个do-nothing表达式语句做什么都不做。
现在对result
顺便说一下,当这个构造用于抑制有关未使用的形式参数的警告时,您可能想要添加名称的重新定义,例如
(void) unusedArg; struct unusedArg;
这可以防止在以后维护代码时无意中使用该参数
但是,visual c ++生成的错误并不完全是信息性的
可以添加无数级别的复杂程度,但我认为即使名称重新定义可能也太过分了 - 成本高于优势,也许
答案 1 :(得分:0)
您可以使用UNREFERENCED_PARAMETER
宏。
答案 2 :(得分:0)
好像我到了某个地方!
#define ASSERT(condition, msg) \
do { \
if (0,0) { \
(void)(condition); \
} \
} while (0,0)
强制性解释:
(void)(condition);
将取消C4189,但会执行传入的任何表达式或函数调用。
然而,if (false) {...}
将确保无论(有效表达式)“......”可能是什么,它都不会被执行。代码优化阶段会将其视为死代码并将其丢弃(在我的测试中根本没有代码生成代码!)。
最后,猫头鹰技巧(0,0)
将阻止C4127,这在一开始似乎是一个非常无用的警告,但嘿,在编译输出中不那么混乱!
我能找到这个解决方案的唯一弱点是condition
需要是可编译的代码,所以如果你#ifdef
- 删除了表达式的一部分,它将引发错误。可能是它还在编译(虽然没有调用)被调用函数的代码;更多的研究将是有用的。
答案 3 :(得分:0)
这样更好。另外:表达式而不是语句
#define ASSERT(condition, msg) ( false ? (void)(condition) : (void)0 )
虽然您可能希望断言的调试版本和发布版本具有相同的语义,因此围绕它的do {...} while (0,0)
可能是合适的。
答案 4 :(得分:0)
您可以使用__pragma(warning(push)) __pragma(warning(disable: 4127))
和__pragma(warning(pop))
对来仅为ASSERT
行静音C4127。
然后(void)(true ? (void)0 : ((void)(expression)))
沉默C4189。
摘自my own implementation of an assertion macro。
PPK_ASSERT(expression)
宏最终将扩展为PPK_ASSERT_3(level, expression)
或PPK_ASSERT_UNUSED(expression)
,具体取决于是启用还是禁用断言。
#define PPK_ASSERT_3(level, expression, ...)\
__pragma(warning(push))\
__pragma(warning(disable: 4127))\
do\
{\
static bool _ignore = false;\
if (PPK_ASSERT_LIKELY(expression) || _ignore || pempek::assert::implementation::ignoreAllAsserts());\
else\
{\
if (pempek::assert::implementation::handleAssert(PPK_ASSERT_FILE, PPK_ASSERT_LINE, PPK_ASSERT_FUNCTION, #expression, level, _ignore, __VA_ARGS__) == pempek::assert::implementation::AssertAction::Break)\
PPK_ASSERT_DEBUG_BREAK();\
}\
}\
while (false)\
__pragma(warning(pop))
和
#define PPK_ASSERT_UNUSED(expression) (void)(true ? (void)0 : ((void)(expression)))