web-dev-qa-db-ja.com

C ++では++ * ptr ++は未定義の動作ですか?

++ * ptr ++の評価について、私はテストで次の質問をしました(私は自分でそれを書きたくありませんでした。テストはそれを求めました。まだ悪いコードがわかっています)。

int Ar[ ] = { 6 , 3 , 8 , 10 , 4 , 6 , 7} ;
int *Ptr = Ar  ;
cout<<++*Ptr++  ;

ただし、これは(++*ptr)++または++(*ptr++)の両方になる可能性があるため、これは未定義の動作であると思います。それは...ですか?私はドキュメンテーションに精通していないので、私は何も見つけることができませんでした。

56
SHM

しかし、これは(++*ptr)++または++(*ptr++)の両方になる可能性があるため、これは未定義の動作であると私は思います。それは...ですか?

実際には、C++での実装自体に十分な余裕を与えるランタイムの振る舞いとは異なり、それ自体は非常に厳密で明確に定義された規則に従います。1。実際、 優先順位規則 を見ると、++*Ptr++は実際には++(*(Ptr++))として解析されます。

代わりに、このトリックな質問は、式の中に複数回現れる値があり、式の副作用による変更を受けるという、 i = ++i + ++i のような式の未​​定義の動作をおそらく暗示しています。表現そのもの。副作用を順序付ける演算子がない限り、そのような式は違法です。2つまり、それらが適用される正確な瞬間は定義されていないので、式のさまざまな点でiがどのような値をとるかは正確には定義されていません。

それでも、式の中のすべての副作用が式の中で一度だけ現れる異なる値に作用するため、未定義の動作はありません。 "inner" ++Ptrに影響し、外側のものは元々Ptrが指す値に影響します、すなわちAr[0]

++(*(Ptr++))
     ^^^^^____increments Ptr, returning its original value
   ^^^^^^^^______dereferences the original Ptr, AKA &Ar[0]
^^^^^^^^^^^^_______ increments Ar[0]

そうは言っても、私たちのコードベースでそのような表現を見たことがあるなら、著者を見つけてこれが二度と起こらないことを確かめるために多くの努力をします。


  1. 場合によっては非常に奇妙で不条理に実装に費用がかかる場合があります。それでも、標準化された未定義の動作のインスタンスが解析のいくつかのコーナーケースを説明していますが、それは "ランタイム"未定義の動作より普及していない桁です。
  2. それらの規則の便利な要約 ここで見つけることができます ;興味深いことに、C++ 17ではいくつかの追加保証が追加されています。
75
Matteo Italia

この

++*Ptr++;

u.Bを引き起こさず、++(*(Ptr++))として評価されます。

  • ptr++;/* address post incremented i.e doesn't change here itself */
  • *ptr;/* dereference same address i.e value at location where ptr earlier pointed i.e 6 */
  • ++*ptr;/* value changed where ptr pointed i.e Ar[0] becomes 7 */

投稿の増分Ptr++は次のように評価されることに注意してください。

  • Ptr;/* Ptr doesn't change here itself in same expression */
  • Ptr = Ptr + 1;/* in next expression, Ptr considers the incremented one */
23
Achal