私はCを学び始めたばかりで、それを理解しています
*a = *b;
a++;
b++;
と
*a++ = *b++
同等ですが、行が実際に起こっていることは何ですか
*a++ = *b++
と呼ばれる?コンパイラが 2 行目をどのように解釈しているかを明確にすることはできますか? 右から左への優先順位などについては知っていますが、コンパイラがこのコード行を解釈するために使用する手順を正確に記述できる人はいますか?
あなたは次のように信じていると言いました:
*a = *b; a++; b++;
と同等です
*a++ = *b++;
しかし、それは間違っているので、あなたは間違った信念を持っています。あなたの誤った信念を正しましょう。
最初のケースでは、次のことが発生する必要があります。
*a
変数を生成するために評価する必要があります。それを呼び出しますvar
*b
値を生成するために評価する必要があります。それを呼び出しますval
val
に割り当てる必要がありますvar
。a
インクリメントする必要があります。b
インクリメントする必要があります。コンパイラがそれらを注文する方法に関する制約は何ですか?
ここでの規則は、次のステートメントが始まる前に、1 つのステートメントのすべての副作用が完了している必要があるということです。したがって、2 つの法的な命令があります。VAR VAL ASSIGN INCA INCB、または VAL VAR ASSIGN INCA INCB。
次に、2 番目のケースを考えてみましょう。
*a++ = *b++;
同じ 5 つの操作がありますが、これらはすべて同じステートメント内にあるため、順序に関する制約はまったく異なります。したがって、ステートメントに関する規則は適用されません。現在、制約は次のとおりです。
a
b
インクリメントは後で行う必要があるとは言っていないことに注意してください。むしろ、元の値を使用する必要があると言いました。 元の値が使用されている限り、インクリメントはいつでも発生する可能性があります。
したがって、たとえば、これを次のように生成することは完全に合法です。
var = a;
a = a + 1; // increment a before assign
*var = *b;
b = b + 1; // increment b after assign
これを行うことも合法です:
val = *b;
b = b + 1; // increment b before assign
*a = val;
a = a + 1; // increment a after assign
あなたが提案するようにそれを行うことも合法です。最初に割り当てを行い、次に両方を左から右の順序でインクリメントします。また、最初に割り当てを行い、次に両方を右から左の順にインクリメントすることも合法です。
AC コンパイラには、コードを生成するための幅広い自由度が与えられていますが、この種の表現は好きです。ほとんどの人はこれを誤解しているので、++
これが頭の中ではっきりしていることを確認してください。インクリメントは、コンパイラーが元の値が使用されることを保証する限り、コンパイラーが好きなだけ早く発生する可能性があります。
これが C および C++ のルールです。C# の言語仕様では、代入の左側の副作用が代入の右側の副作用の前に発生し、両方とも代入の副作用の前に発生する必要があります。C# の同じコードを次のように生成する必要があります。
var_a = a;
a = a + 1;
// must pointer check var_a here
var_b = b;
b = b + 1;
val = *var_b; // pointer checks var_b
*var_a = val;
「ポインター チェック」は、C# がランタイムvar_a
に有効なポインターであることを確認する必要があるポイントです。つまり、これ*var_a
は実際には変数です。そうでない場合は、評価される前に例外をスローする必要があります。 b
繰り返しますが、C コンパイラはC# の方法で実行できますが、必須ではありません。
1)
*a = *b;
a++;
b++;
と同等です
*a = *b;
a = a+1;
b = b+1
2)
x = *a++
と同等です
x = *a;
a = a+1;
と
*b++ = x
と同等です
*b = x;
b = b+1;
それで
*a++ = *b++
と同等です
*a = *b;
a = a+1;
b = b+1
3)
*(++a) = *(++b)
と同等です
a = a+1;
b = b+1
*a = *b;