2

かなりのデバッグ時間の後、私は自分のコードに次のような問題があることを発見するのはばかげていると感じました:

int main()
{
    double p1[] = { 1, 2, 3 };
    double p2[] = { 1, 2, 3 };
    int color = 1;
    bool some_condition = true;

    if (some_condition) (p1, p2, color);
}

式は(p1, p2, color)最後のオペランドに評価されますが、コンパイラは何らかの方法で私を保護する必要がありますか? (Visual Studioは何も言わなかった)

はい、あなたはそれを正しく推測しました。私は描画関数を呼び出したかったのです:Draw(p1, p2, color)

4

2 に答える 2

4

C++ では、この式により、コンパイラは括弧内のコンマを逐次評価演算子(p1, p2, color)として解釈するように強制されます。順次評価演算子は、最初のオペランドを評価して結果を破棄する二項演算子です。次に、2 番目のオペランドを評価し、その値と型を返します。したがって、式は次のように評価されます。void(p1, p2, color)

  1. 最初p1に が評価されて破棄され、次に(p2, color)が評価されて結果(p2, color)が返されます。
  2. 最初p2に が評価されて破棄され、次にcolorが評価されて結果colorが返されます。

したがって、ステートメント:

if (some_condition) (p1, p2, color);

以下と同等です。

if (some_condition) color;

一部のコンパイラでは、式(p1, p2, color)の評価中にp1との評価がp2未使用になるため、警告が発生する場合があります。

CLANG LIVE DEMO GCC LIVE DEMO (既に述べたように、Visual Studioでは警告はまったく発生しません。)

これらの警告を除けば、コードは正当な C++ です (つまり、C++ 構文に違反していません)。

さて、コンパイラがあなたを保護すべきかどうかは議論の余地があります。私の謙虚な意見では、そのような式は C++ 構文の観点からは正しくても、バグを見つけるのが非常に困難になる可能性があるため (たとえば、式内の代入の場合)、それはあなたを保護するはずですif

于 2014-07-28T13:46:20.703 に答える
3

これは完全に有効なコードであるため、コンパイラは診断を発行する必要はありませんが、この場合は診断が役立ちます。これは、多くの開発者が好む理由の 1 つです。なぜなら、彼らは診断に関して必要以上のことclangをする傾向があるからです。

診断メッセージに関する標準ルールについては、ドラフト C++ 標準セクションの1.4 実装コンプライアンスに移動できます (強調鉱山):

  1. 診断可能な規則のセットは、この国際標準のすべての構文規則と意味規則で構成されます。ただし、「診断は必要ありません」という明示的な表記を含む規則、または「未定義の動作」をもたらすと記述されている規則は除きます。</p>

  2. この国際標準は C++ 実装に関する要件のみを述べていますが、それらの要件は、プログラム、プログラムの一部、またはプログラムの実行に関する要件として表現されている場合、理解しやすいことがよくあります。このような要件には、次の意味があります。

    • プログラムにこの国際標準の規則違反が含まれていない場合、適合する実装は、そのリソース制限内で、そのプログラムを受け入れて正しく実行する必要があります。

    • 実装がその構成をサポートしていないときに、プログラムが診断可能な規則の違反、またはこの標準で「条件付きでサポートされる」と記述されている構成の発生を含む場合、適合する実装は少なくとも 1 つの診断メッセージを発行するものとします。

    • プログラムに診断が不要な規則違反が含まれる場合、この国際規格はそのプログラムに関する実装に要件を課しません。

このプログラムは構文上または意味上の規則に違反していないため、診断は必要ありません。

次のコードがあります。

if (some_condition) (p1, p2, color);
                    ^  ^   ^
                    1  2   3

1このコンテキストで有効な式ステートメント for およびifステートメントです。これは、文法を見ればわかります。

if ( condition ) statement

と:

statement:
  attribute-specifier-seqopt expression-statement

と:

expression-statement:
  expressionopt;

と:

primary-expression:
  ( expression )

23は両方とも、左のオペランドを評価して値を破棄し、右のオペランドを再度評価するコンマ演算子です。ここでは無効ではありません。

では、セクション5.18 コンマ演算子は次のように言っています。

コンマで区切られた式のペアは、左から右に評価されます。左の式は破棄された値の式です (箇条 5)。83

破棄された値式は、次のセクション5で説明されています。

一部のコンテキストでは、式はその副作用のためにのみ表示されます。このような式は、破棄値式と呼ばれます。

したがって、左側の式の結果の値は破棄されるため、副作用のみを気にする必要があります。あなたの特定のケースでは、変数を評価しても、値を生成する以外に他の効果はないため、警告が表示されますが、代わりに関数を使用した場合は、次のようになります。

bool func()
{
    //...
}

コードを次のように変更します。

if (some_condition) (func(), func(), func() );

おそらくあなたが気にかけているいくつかの副作用を実行するので、どちらclanggcc警告も提供しません。func

于 2014-07-28T14:03:17.517 に答える