C/C++:如何使用do-while(0); 构造没有编译器警告,如C4127?

bia*_*lix 44 c c++ macros compiler-warnings visual-c++

由于本答案中描述的原因,我经常在我的#defines中使用do-while(0)构造.此外,我正在尝试使用尽可能高的编译器警告级别来捕获更多潜在问题,并使我的代码更加健壮和跨平台.所以我通常使用-Wallgcc和/WallMSVC.

不幸的是,MSVC抱怨do-while(0)构造:

foo.c(36) : warning C4127: conditional expression is constant
Run Code Online (Sandbox Code Playgroud)

我应该怎么做这个警告?

只是为所有文件全局禁用它?对我来说这似乎不是一个好主意.

Pav*_*sky 45

简介:在这种特殊情况下,此警告(C4127)是一个微妙的编译器错误.随意禁用它.

深入:

它的目的是捕获逻辑表达式在非显而易见的情况下评估为常量的情况(例如if(a==a && a!=a),在某种程度上,它转变为while(true)其他有用的构造变为无效.

for(;;)如果您想要启用此警告,Microsoft建议使用无限循环,并且您的案例没有解决方案.这是我公司的开发惯例允许禁用的极少数Level-4警告之一.


Eri*_*nen 28

也许你的代码需要更多的猫头鹰:

do { stuff(); } while (0,0)
Run Code Online (Sandbox Code Playgroud)

或者较少上镜而且警告产生较少:

do { stuff(); } while ((void)0,0)
Run Code Online (Sandbox Code Playgroud)

  • @bialix:可以像这样轻松修复:`do {} while((void)0,0)` (8认同)
  • 有趣,但实际上没有帮助。它会产生另一个警告 :-) 警告 C4548:逗号之前的表达式无效;具有副作用的预期表达 (2认同)
  • 在(stuff()`之后不应该有分号吗? (2认同)

Mic*_*ter 17

正如Michael BurrCarl Smotricz回答所说,对于Visual Studio 2008+,您可以使用__pragma:

#define MYMACRO(f,g)              \
  __pragma(warning(push))         \
  __pragma(warning(disable:4127)) \
  do { f; g; } while (0)          \
  __pragma(warning(pop))
Run Code Online (Sandbox Code Playgroud)

\如果您希望宏不可读,可以将它放在一行(没有s).

  • 推送在这里做得太早 - 如果你仍想在`f`和`g`语句中捕获问题,你需要在`while(0)`之前立即执行警告.有关隐约重用的内容,请参阅其他MULTI_LINE_MACRO答案. (3认同)

nev*_*lis 15

我有一个模式,我基于这里的答案,它适用于clang,gcc和MSVC.我在这里发帖,希望它对其他人有用,因为这里的答案帮助我制定它.

#ifdef WIN32
#  define ONCE __pragma( warning(push) ) \
               __pragma( warning(disable:4127) ) \
               while( 0 ) \
               __pragma( warning(pop) )
#else
#  define ONCE while( 0 )
#endif
Run Code Online (Sandbox Code Playgroud)

我这样使用它:

do {
   // Some stuff
} ONCE;
Run Code Online (Sandbox Code Playgroud)

您也可以在宏中使用它:

void SomeLogImpl( const char* filename, int line, ... );    

#ifdef NDEBUG
#  define LOG( ... )
#else
#  define LOG( ... ) do { \
      SomeLogImpl( __FILE__, __LINE__, __VA_ARGS__ ); \
   } ONCE
#endif
Run Code Online (Sandbox Code Playgroud)

如果F在函数中使用'ONCE',这也适用于上面指出的情况:

#define F( x ) do { f(x); } ONCE
...
if (a==b) F(bar); else someFunc();
Run Code Online (Sandbox Code Playgroud)

编辑:多年以后,我意识到我忘了添加我实际编写这个宏的模式 - "switch-like-a-goto"模式:

do {
    begin_some_operation();

    if( something_is_wrong ) {
        break;
    }

    continue_big_operation();

    if( another_failure_cond ) {
        break;
    }

    finish_big_operation();
    return SUCCESS;
} ONCE;

cleanup_the_mess();
return FAILURE;
Run Code Online (Sandbox Code Playgroud)

这给你一个try/finally-ish结构,它比你的清理和返回代码更加结构化.使用此ONCE宏而不是while(0)将关闭VS.


小智 5

使用较新版本的 MS 编译器,您可以使用警告抑制:

#define MY_MACRO(stuff) \
    do { \
        stuff \
    __pragma(warning(suppress:4127)) \
    } while(0)
Run Code Online (Sandbox Code Playgroud)

您也可以推送/禁用/弹出,但抑制是一种更方便的机制。

  • 更方便的错误解决机制,而不是修复错误。干得好! (2认同)