i=++i+1;
を読み解く
はじめに
この記事はC11に則っています.
また,この記事の正当性を保証するものは何もありませんし,正しく読み解けているかはわかりません.むしろどこか間違っています.間違いがあったらコメントで教えてください.
注釈84が理解できない人向け.
読解
副作用完了点について.
この文の副作用完了点は文末の;
なので,ここまでに副作用が完了していれば良い.
i=++i+1
この式は,まずi
,=
,++i+1
の部分式に分解され,右辺は++i
,+
,1
に分解される.
部分式の評価順序は不定であることから,i
と++i+1
,また++i
と1
の評価順序は不定である.
また,オペランドの値の計算は,オペレータの結果による値の計算より前に順序付けられる.
単純代入
i
は算術型(と仮定します.多分intでしょう)であり,++i+1
も同様なので,単純代入の制約を満たす.
i
の値を++i+1
にする,という副作用を持ち,この副作用は6.5.16より,左右のオペランドの値の計算後に順序づけられる.
しかし,単純代入の式を評価した値とこの副作用の間には,評価順序は存在しない.
すなわち,i=4+2
という式を評価した値は6だが,実際にi
が6になるのはi
と4+2
を評価した後ならいつでも良い.
i
と++i+1
i
と++i+1
に分解され,これらの値の計算は不定である.しかし,左辺のi
が指し示すオブジェクトは右辺の評価によって変わらない(はず.++iしても&iには関係ないと思う).よって,++i+1
に注目する.
ここまでで確定している順序
()の中の評価順序は不定.
((i
の値の計算,++i+1
の値の計算)→i=++i+1
の値の計算,i
の値を++i+1
にするという副作用)
++i
と1
++i
の型はi
と同じであり,i
は算術型であり,1
はint型なので6.5.6の制約を満たす.
二項+
演算子の結果は左右のオペランドの和である.
++i
の値の計算と1
の値の計算は++i+1
の値の計算より前に行われる.
ここまでで確定している順序
((i
の値の計算,{++i
の値の計算,1
の値の計算→++i+1
の値の計算})→i=++i+1
の値の計算,i
の値を++i+1
にするという副作用)
++i
6.5.3より,++iはi+=1と等価である.
よって最初の式はi=(i+=1)+1
のように変形できる.
i
は算術型なので+=
の制約を満たし,i+=1
はi
が1回しか評価されないことを除きi=i+1
と等価なので,単純代入の式に帰着し,最初の式は,i=(i=i+1)+1
となる.
これは,i
の値をi+1
にする,という副作用を持ち,この副作用は左右のオペランドの値の計算後に順序付けられる.
ここまでで確定している順序
((i
の値の計算,{[<`i`の値の計算,`1`の値の計算>→`i=i+1`の値の計算],`1`の値の計算→`++i+1`の値の計算})→`i=++i+1`の値の計算,`i`の値を`++i+1`にするという副作用,<…>→i
の値をi+1
にするという副作用)
これがi=++i+1
を実行した時に起こることで,すべての副作用は,副作用完了点までに実行される.
結論
((…,{[<…>→…],…→…})→…,`i`の値を`++i+1`にするという副作用,<…>→i
の値をi+1
にするという副作用)
となり,i
の値を++i+1
にするという副作用とi
の値をi+1
にするという副作用がどのような順序で実行されるかわからないため,6.5より未定義となる.