Visual Studio 2010 SP1中的断言和未使用的变量

时间:2013-04-04 18:47:56

标签: c++ visual-studio-2010 macros assert

我在“发布”中使用下面的代码断言,有一段时间没有任何问题。 然后是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)resultif (result == result) {}UNREFERENCED_PARAMETER(result)(或等效)这样的脚手架代码,只是为了避免警告,因为它会使代码变得更难阅读(污染),在Debug中编写代码时很容易忘记。还有:在很多地方!

我正在考虑为变量创建另一个宏(ASSERTU?),但感觉如此......古怪! 有没有人找到更好的出路?

非常感谢!

编辑:明确了调用者级别变量处理的首选项

5 个答案:

答案 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)))