12

シーケンス ポイントについて読んだ後、i = ++i未定義であることを知りました。

では、次のコードはどうでしょうか。

int i;
int *p = &i;
int *q = &i;
 *p = ++(*q);           // that should also be undefined right?

p と q の初期化が何らかの (複雑な) 条件に依存しているとします。そして、それらは上記の場合のように同じオブジェクトを指している可能性があります。何が起こるか?定義されていない場合、どのツールを使用して検出できますか?

編集: 2 つのポインターが同じオブジェクトを指していない場合、C99 制限を使用できますか? それは「厳格」の意味ですか?

4

5 に答える 5

12

Yes, this is undefined behavior -- you have two modifications of an object without a sequence point between them. Unfortunately, checking for this automatically is very hard -- the best I can think of is adding assert(p != q) right before this, which will at least give a clean runtime fault rather than something worse. Checking this at compile time is undecidable in the general case.

于 2010-08-26T00:47:35.993 に答える
4

検出するのではなく、そもそもこれを回避するための最良のツールは、優れたプログラミング手法を使用することです。副作用を回避し、割り当てごとに複数の書き込みを行わないようにします。何も問題はありません

*q += 1;
*p = *q;
于 2010-08-26T05:46:10.423 に答える
2

The expression is the same as i=++i. The only tool that can detect it is your head. In C with power comes responsibility.

于 2010-08-26T00:47:17.503 に答える
2

第 5 章 式

ポイント 4:

特に明記されていない限り、個々の演算子のオペランドと個々の式の部分式の評価の順序、および副作用が発生する順序は規定されていません。前のシーケンス ポイントと次のシーケンス ポイントの間で、スカラー オブジェクトの格納値は、式の評価によって最大 1 回変更されます。さらに、保存する値を決定するためにのみ、前の値にアクセスする必要があります。この段落の要件は、完全な式の部分式の許容される順序ごとに満たされるものとします。それ以外の場合、動作は未定義です。

[ Example:
  i = v[i ++];           / / the behavior is undefined
  i = 7 , i++ , i ++;    / / i becomes 9
  i = ++ i + 1;          / / the behavior is undefined 
  i = i + 1;             / / the value of i is incremented
—end example ]

結果として、これは未定義の動作です:

int i;
int *p = &i;
int *q = &i;
*p = ++(*q);   // Bad Line

「Bad Line」では、式の評価中にスカラー オブジェクト「i」が複数回更新されます。オブジェクト「i」が間接的にアクセスされるからといって、ルールは変わりません。

于 2010-08-26T05:40:29.700 に答える
1

それは良い質問です。あなたが強調したことの1つは、このサイトから引用する「シーケンスポイント」です

次のような式に依存できない理由: a[i] = i++; 代入演算子、インクリメント演算子、またはインデックス演算子にシーケンス ポイントが指定されていないため、i に対するインクリメントの効果がいつ発生するかわかりません。

さらに、上記の式も同様に同じであるため、動作は未定義です。それを追跡するツールはゼロです。例として名前を付けるスプリントは確かにありますが、C 標準なので、隠れている可能性があります。まだ聞いたことのないツールのオプション、おそらくGimpelの PC Lint またはRiverbladeの Visual lint が役立つかもしれませんが、この点に関して未定義の動作を追跡することについては何も言及していないことを認めます.

ちなみに、GCC のコンパイラ バージョン 4.3.3 には-Wsequence-point、フラグを立てる警告の一部としてこのオプションがあります..これは私の Slackware 13.0 ボックスにあります...

コードは肉眼では問題ないように見え、問題なくコンパイルされますが、後で頭痛の種になる可能性があることを示しているだけです。それを行う最善の方法は、コンパイラが認識できない可能性のあるものを見つけることができるコードレビューを行うことです.それが最高の武器です!

于 2010-08-26T00:59:42.713 に答える