14

答えは「いいえ」だと思いますが、コンパイラの観点からは、その理由がわかりません。

私は非常に単純なコードを作成しましたが、これはコンパイラの診断をかなりひどく狂わせます (clang と gcc の両方)。これらはコンパイラのバグではないことを指摘しておく必要があります。出力はすべての場合に正しいですが、警告については疑問があります。

次のコードを検討してください。

#include <iostream>

int main(){
  int b,a;
  b = 3;
  b == 3 ? a = 1 : b = 2;
  b == 2 ? a = 2 : b = 1;
  a = a;
  std::cerr << a << std::endl;
}

の割り当てaはトートロジーです。これaは、 が に関係なく、2 つの 3 項ステートメントの後に初期化されることを意味しbます。GCC はこのコードに完全に満足しています。Clang は少し賢く、ばかげたこと ( warning: explicitly assigning a variable of type 'int' to itself [-Wself-assign]) を見つけますが、大したことではありません。

これで (少なくとも意味的には) 同じことですが、構文が短くなります。

#include <iostream>

int main(){
  int b,a = (b=3, 
             b == 3 ? a = 1 : b = 2, 
             b == 2 ? a = 2 : b = 1, 
             a);
  std::cerr << a << std::endl;
}

現在、コンパイラはまったく異なる警告を表示します。Clang はもはや奇妙なことを報告しません (これは、括弧の優先順位のため、おそらく正しいでしょう)。gcc はもう少し恐ろしく、次のように述べています。

test.cpp: In function ‘int main()’:
test.cpp:7:15: warning: operation on ‘a’ may be undefined [-Wsequence-point]

しかし、それは本当ですか?このシーケンス ポイントの警告は、コンマ区切りのステートメントが実際には同じように処理されないというヒントを与えてくれますが、そうすべきかどうかはわかりません。

そして、コードを次のように変更すると、さらに奇妙になります。

#include <iostream>

int main(){
  int b,a = (b=3, 
             b == 3 ? a = 1 : b = 2, 
             b == 2 ? a = 2 : b = 1, 
             a+0); // <- i just changed this line
  std::cerr << a << std::endl;
}

そして突然、clang は何か怪しいものがあるかもしれないことに気付きましたa:

test.cpp:7:14: warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]
             a+0);
             ^

しかし、以前は問題がありませんでしたa...いくつかの理由で、この場合、clang はトートロジーを見つけることができません。繰り返しますが、それは単に、それらが完全なステートメントではないためかもしれません。

問題は次のとおりです。

  • このコードは有効で、適切に定義されていますか (すべてのバージョンで)?
  • コンマ区切りのステートメントのリストはどのように処理されますか? 明示的なステートメントを含むコードの最初のバージョンとは異なる必要がありますか?
  • GCC は未定義の動作とシーケンス ポイントの問題を報告する権利がありますか? (この場合、clang にはいくつかの重要な診断が欠けています) may と表示されていることは承知しています、それでも...
  • a最後のケースで初期化されていない可能性があると報告するのはclangの権利ですか? (その後、前のケースと同じ診断が必要です)

編集とコメント:

  • このコードは単純ではないという (正当な) コメントがいくつか寄せられています。これは事実ですが、ポイントは、初期化子でコンマ区切りのステートメントに遭遇すると、コンパイラが誤診することです。これは悪いことです。「この構文を試してみました...」というコメントを避けるために、コードをより完全なものにしました。より現実的で人間が読める問題のバージョンを書くこともできますが、それは間違った診断を示しますが、このバージョンはより多くの情報を示し、より完全であると思います。
  • コンパイラ拷問テストスイートでは、これは非常に理解しやすく読みやすいと考えられますが、はるかに悪いことをします:) コンパイラをテストして評価するには、そのようなコードが必要です。これは製品コードでは見栄えがよくありませんが、ここでのポイントではありません。
4

1 に答える 1

1

5式

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

5.18 コンマ演算子 [expr.comma]

コンマで区切られた式のペアは、左から右に評価されます。左の式は破棄された値の式です (条項 5)。83 左の式に関連付けられたすべての値の計算と副作用は、右の式に関連付けられたすべての値の計算と副作用の前に並べられます。結果の型と値は、右側のオペランドの型と値です。結果は、右オペランドと同じ値カテゴリであり、右オペランドが glvalue とビット フィールドの場合はビット フィールドです。

あなたの発言には何の問題もないように思えます。

g++ の警告を詳しく見ると、未定義の可能性a=1があります。これは、パーサーが、評価されることが保証されていることを確認するほど賢くないことを示しています。

于 2013-05-28T18:58:16.430 に答える