44

この回答 で説明されている理由により、#defines で do-while(0) コンストラクトを使用することがよくあります。また、コンパイラからの可能な限り高い警告レベルを使用して、より潜在的な問題をキャッチし、コードをより堅牢でクロスプラットフォームにしようとしています。したがって、私は通常-Wall、gcc と/WallMSVC を使用しています。

残念ながら、MSVC は do-while(0) コンストラクトについて不平を言っています。

foo.c(36) : warning C4127: conditional expression is constant

この警告についてどうすればよいですか?

すべてのファイルに対してグローバルに無効にするだけですか? それは私にとって良い考えではないようです。

4

21 に答える 21

46

概要: この特定のケースでのこの警告 (C4127) は、微妙なコンパイラのバグです。自由に無効にしてください。

詳細:

これは、論理式が明白でない状況で定数に評価される状況をキャッチすることを目的としていました (たとえばif(a==a && a!=a)while(true)

Microsoftfor(;;)は、この警告を有効にしたい場合に無限ループを使用することをお勧めしますが、その場合の解決策はありません。これは、私の会社の開発規則で無効にできる数少ないレベル 4 警告の 1 つです。

于 2009-12-22T13:51:01.337 に答える
28

おそらくあなたのコードにはもっとフクロウが必要です:

do { stuff(); } while (0,0)

または、フォトジェニック性は低くなりますが、警告も少なくなります。

do { stuff(); } while ((void)0,0)
于 2009-12-22T15:51:25.480 に答える
18

Michael BurrがCarl Smotriczanswerで指摘したように、Visual Studio 2008 以降では __pragma を使用できます

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

\マクロを読み取れないようにする場合は、(s なしで) 1 行に記述できます。

于 2011-01-27T12:37:31.930 に答える
5

新しいバージョンの MS コンパイラを使用すると、警告の抑制を使用できます。

#define MY_MACRO(stuff) \
    do { \
        stuff \
    __pragma(warning(suppress:4127)) \
    } while(0)

プッシュ/無効化/ポップすることもできますが、抑制ははるかに便利なメカニズムです。

于 2014-09-11T19:00:17.717 に答える
3

このコンパイラのバグは、リリース ノートに記載されていなくても、Visual Studio 2015 Update 1 で修正されました。

ただし、バグは以前の回答の1つで説明されていました。

概要: この特定のケースでのこの警告 (C4127) は、微妙なコンパイラのバグです。自由に無効にしてください。

これは、論理式が非自明な状況 (if(a==a && a!=a) など) で定数に評価される状況をキャッチすることを意図しており、どういうわけか、while(true) およびその他の有用な構造を無効にしました。 .

于 2016-04-16T00:21:29.810 に答える
2

使用できます

do {
    // Anything you like
} WHILE_FALSE;

そして、以前に次のWHILE_FALSEようにマクロを定義します。

#define WHILE_FALSE \
    __pragma(warning(push))         \
    __pragma(warning(disable:4127)) \
    while(false)                    \
  __pragma(warning(pop))

MSVC++2013 で検証済み。

于 2016-08-24T08:03:54.473 に答える
2

警告は によるものwhile(false)です。このサイトでは、この問題を回避する方法の例を示しています。サイトの例 (コードに合わせて作り直す必要があります):

#define MULTI_LINE_MACRO_BEGIN do {  
#define MULTI_LINE_MACRO_END \  
    __pragma(warning(push)) \  
    __pragma(warning(disable:4127)) \  
    } while(0) \  
    __pragma(warning(pop))

#define MULTI_LINE_MACRO \  
        MULTI_LINE_MACRO_BEGIN \  
            std::printf("Hello "); \  
            std::printf("world!\n"); \  
        MULTI_LINE_MACRO_END  

BEGIN と END の間にコードを挿入するだけです。

于 2012-08-20T18:54:16.550 に答える
1

式で使用されるマルチステートメント マクロには、do-while(0) コンストラクトの代わりにコンマ演算子を使用できます。したがって、代わりに:

#define FOO(...)    do { Statement1; Statement2; Statement3; } while(0)

使用する:

#define FOO(...)    (Statement1, Statement2, Statement3)

これはプラットフォームとは独立して機能し、コンパイラの警告を回避できます (最高の警告レベルが選択されている場合でも)。マクロを含むコンマ (2 番目の FOO) では、最後のステートメント (Statement3) の結果がマクロ全体の結果になることに注意してください。

于 2013-10-07T16:21:16.430 に答える
1

#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)?

#define STUFF for (;;) {f(); g(); break;}?

于 2009-12-22T14:52:50.510 に答える
1

この "while(0)" はハックであり、あなたを噛むために振り向いたところです。

コンパイラは、#pragma特定のエラー メッセージを選択的かつローカルにオフにする を提供していますか? もしそうなら、それは賢明な選択肢かもしれません。

于 2009-12-22T13:45:48.787 に答える
0

私は、マクロの do..while 構文を気にしたことは一度もないと言わざるを得ません。マクロ内のすべてのコード自体は中かっこで囲まれていますが、do-..while はありません。例えば:

#define F(x) \
    {           \
        x++;    \
    }           \

int main() {
    int a = 1;
    F(a);
    printf( "%d\n", a );
}

また、私自身のコーディング標準 (そして何年にもわたる非公式の慣行) では、すべてのブロックを中かっこで囲むようにしています。これにより、多かれ少なかれ問題が解消されます。

于 2009-12-22T13:50:32.040 に答える
0

#pragma warning を使用して、次のことができます。

  1. 状態を保存する
  2. 警告を無効にする
  3. 問題のあるコードを書く
  4. 警告を以前の状態に戻す

(プラグマの前に # が必要ですが、SO はプラグマの処理とフォーマットを同時に行うのに苦労しています)

#pragma warning( push )
#pragma warning( disable: 4127 )
// Your code
#pragma warning( pop ) 

警告をオン/オフするために選択される可能性のあるコマンドライン引数に干渉したくないため、警告を無効/有効にするのではなく、プッシュ/ポップする必要があります (誰かがコマンドラインを使用して警告をオフにする可能性があります。強制的に元に戻したくありません...上記のコードはそれを処理しています)。

これは、必要な部分だけを制御できるため、警告をグローバルにオフにするよりも優れています。また、マクロの一部にすることもできます。

于 2009-12-22T14:31:13.967 に答える
0

解決策はありますが、コードにさらにサイクルが追加されます。while 条件で明示的な値を使用しないでください。

次のように作成できます。

file1.h

extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) \
do \
{ \
} \
while(I_am_a_zero);

変数 I_am_a_zero は、何らかの .c ファイルで定義する必要があります。

とにかく、この警告はGCCには表示されません:)

この関連する質問を参照してください。

于 2009-12-22T16:24:07.097 に答える
0

これにより、警告が無効になり、コンパイラは引き続きコードを最適化できます。

static inline bool to_bool(const bool v) { return v; }

if (to_bool(0)) { // no warning here
    dead_code(); // will be compiled out (by most compilers)
}

do { something(); } while(to_bool(0)); // no extra code generated
于 2015-12-19T22:16:55.060 に答える
0

これが最も短いバージョンであることがわかりました

do {
  // ... 
}
while (([]() { return 0; })())  /* workaround for MSVC warning C4172 : conditional expression is constant */

コンパイラによって最適化されているかどうかは確認していませんが、そうだと思います。

于 2016-02-09T10:09:08.823 に答える
-1

私が使用します

for(int i = 0; i < 1; ++i) //do once
{

}

これは同等です

do
{
}while(0);

警告は表示されません。

于 2012-10-19T08:54:03.443 に答える
-1

プロジェクトでこの警告を無効にするには、コンパイラ スイッチ/wd"4127"を使用してください。

于 2020-02-03T09:47:30.630 に答える