C99標準では、変数を自分自身に割り当てることができますか? たとえば、次は有効ですか。
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
ケース 1 は有効だと思いますが、ケース 2 についても同じことを言うのはためらいがあります。
代入の場合、左側の変数に値を代入する前に右側が完全に評価されますか? または、代入される変数へのポインターを逆参照するときに競合状態が発生しますか?
C99標準では、変数を自分自身に割り当てることができますか? たとえば、次は有効ですか。
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
ケース 1 は有効だと思いますが、ケース 2 についても同じことを言うのはためらいがあります。
代入の場合、左側の変数に値を代入する前に右側が完全に評価されますか? または、代入される変数へのポインターを逆参照するときに競合状態が発生しますか?
a
の値は格納される値を決定するためにのみ使用され、この値が格納されるオブジェクトを決定するためには使用されないため、どちらの場合も完全に有効です。
本質的に、割り当てでは、3 つの異なる操作を区別する必要があります。
これら 3 つの操作のうち最初の 2 つは、任意の順序で実行でき、並列でも実行できます。3 つ目は、明らかに他の 2 つの結果であるため、後で発生します。
これは完全に有効です。以前の値のみを使用して、保存する値を決定しています。これは、ドラフト C99 標準セクションでカバーされており、次の6.5.2
ように書かれています。
前のシーケンス ポイントと次のシーケンス ポイントの間で、オブジェクトは格納された値を式の評価によって最大 1 回変更する必要があります。
有効なコードの例の 1 つを次に示します。
i = i + 1;
ここの C および C++ セクションでは、シーケンス ポイントが発生するさまざまな場所について説明します。
C99 6.5.16.1 単純代入
3 オブジェクトに格納されている値が、最初のオブジェクトのストレージとオーバーラップする別のオブジェクトから読み取られる場合、オーバーラップは正確であり、2 つのオブジェクトは互換性のある型の修飾バージョンまたは非修飾バージョンを持つ必要があります。それ以外の場合、動作は未定義です。
サンプルコードは「重複」条件を満たしていると思います。互換性のある型の修飾されたバージョンがあるため、結果は有効です。
6.5.16 代入演算子も
4 オペランドの評価順序は規定されていません。代入演算子の結果を変更しようとしたり、次のシーケンス ポイントの後にアクセスしようとした場合の動作は未定義です。
それでも、「結果を変更しようとする試み」がないため、結果は有効です。