2

我在“发布”中使用下面的代码进行断言,已经有一段时间没有问题了。然后出现了 Visual Studio 2010 Pro SP1,事情向南发展了,先生也发生了。克伦塔尔

问题是,当我有一段代码可以进行这样的健全性检查时:

#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)将执行作为条件传递的任何表达式,这是一个否否
  • 放入ASSERTCallMeOnce()表达式是不可能的
  • 重构所有不同CallMeOnce()的 s 不是一种选择
  • 我宁愿不必为了避免警告而在宏之外编写类似(void)result,if (result == result) {}UNREFERENCED_PARAMETER(result)(或等效)的脚手架代码,因为它使代码更难阅读(污染),并且在 Debug 中编写代码时很容易忘记。另外:在很多地方!

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

非常感谢!

编辑:澄清了对调用者级别的变量处理的偏好

4

5 回答 5

0

在你的断言宏中你有

(void)sizeof(condition);

大概这段代码是别人写的,所以,解释一下:

演员表的作用(void)是告诉编译器你真的想让这个无所事事的表达式语句什么都不做。

现在为你做同样的事情result

这很容易,不是吗?有时解决方案只是盯着你的脸。;-)


顺便说一句,当这个结构被用来抑制关于未使用的形式参数的警告时,你可能想要添加一个重新定义的名字,比如

(void) unusedArg; struct unusedArg;

这可以防止在以后维护代码时无意中使用该参数

但是,Visual C++ 产生的错误信息并不完全


可以添加无数复杂程度,但我认为即使重新定义名称也可能太过分了——成本大于优势,也许

于 2013-04-04T18:59:12.113 回答
0

您可以使用UNREFERENCED_PARAMETER宏。

于 2013-04-04T19:03:37.623 回答
0

看来我到了某个地方!

#define ASSERT(condition, msg) \
  do { \
    if (0,0) { \
      (void)(condition); \
    } \
  } while (0,0)

强制解释

(void)(condition);将抑制 C4189,但将执行传入的任何表达式或函数调用。

但是,if (false) {...}将确保无论(有效表达式)“...”是什么,它都不会被执行。代码优化阶段会将其视为死代码并将其丢弃(在我的测试中根本没有为块生成代码!)。

最后,猫头鹰技巧(0,0)将阻止 C4127,这首先似乎是一个非常无用的警告,但是嘿,编译输出中的混乱更少!

我能找到这个解决方案的唯一弱点是它condition需要是可编译的代码,所以如果你#ifdef- 删除了部分表达式,它会引发错误。可能它也在编译(虽然不是调用)被调用函数的代码;更多的研究将是有用的。

于 2013-04-05T17:23:13.557 回答
0

这要好得多。另外:表达式而不是语句

#define ASSERT(condition, msg) ( false ? (void)(condition) : (void)0 )

尽管您可能希望断言的调试版本和发布版本都具有相同的语义,但do {...} while (0,0)围绕它的 a 可能是合适的。

于 2013-04-12T11:03:56.047 回答
0

您可以使用成对的__pragma(warning(push)) __pragma(warning(disable: 4127))__pragma(warning(pop))来使 C4127 静音ASSERT

然后(void)(true ? (void)0 : ((void)(expression)))使 C4189 静音。

这是我自己实现的断言宏的摘录。

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)))
于 2015-12-05T10:20:39.237 回答