半分冗談半分真面目:++i++
C ライクな言語、特に C# でできないのはなぜですか?
値をインクリメントし、それを式で使用してから、再度インクリメントすることを期待しています。
半分冗談半分真面目:++i++
C ライクな言語、特に C# でできないのはなぜですか?
値をインクリメントし、それを式で使用してから、再度インクリメントすることを期待しています。
「左辺値ではない」という短い答えは正しいですが、それはおそらく質問を請うだけです。左辺値ではないのはなぜですか? または、C# で言うように、変数.
その理由は、ケーキを持って食べられないからです。論理的に解決してください:
まず、C# での ++ 演算子の意味は、接尾辞であろうと接頭辞であろうと、「この変数の値を取得し、値をインクリメントし、新しい値を変数に割り当て、結果として値を生成する」です。結果として生成される値は、接尾辞か接頭辞かに応じて、元の値または増分された値のいずれかになります。しかし、いずれにせよ、あなたは価値を生み出します。
次に、変数の値は常にその変数の現在の内容です。(私たちをはるかに遠くへ連れて行く、特定の奇妙なスレッドシナリオをモジュロします。)
これらが完全に賢明なルールであることに同意していただければ幸いです。
これで、i++ の結果が変数にならない理由が明らかになったはずですが、そうでない場合に備えて、はっきりさせておきます。
i が 10 であると仮定します。i++ の意味は、「i の値を取得する — 10 — インクリメントする — 11 — 保存する — i は現在 11 です — 元の値を結果として与える — 10」です。したがって、print(i++) と言うと、10 が出力され、11 が i に格納されます。
ここで、i++ の意味が、値ではなく変数を返すことであるとします。print(i++) と言うとどうなりますか? i の値を取得 — 10 — インクリメント — 11 — 保存 — i は現在 11 であり、結果として変数を返します。変数の現在の値は? 11!これはまさに印刷したくないものです。
つまり、i++ が変数を返した場合、演算子の意図した意味とは正反対のことを行っていることになります! あなたの提案は論理的に矛盾しています。そのため、どの言語もそのようにはなりません。
短い答え:i++
は「左辺値」ではないため、割り当ての対象にすることはできません。
人気のある慣習に逆らって解雇された後も、次のプログラマーがあなたのコードを保守する (または書き直そうとする) ことを心配しているからです。
回避策として (++i,i++) をテストしました:
#include <stdio.h>
int main(){
int i=0;
printf(" i: %i\n", i );
printf(" (++i,i++): %i\n", (++i,i++) );
printf(" i: %i\n", i );
}
結果:
i: 0
(++i,i++): 1
i: 2
の結果はi++
左辺値ではないためです。
インクリメント(またはデクリメント)演算子には、割り当てる左辺値が必要だと思います。ただし、 ++i は左辺値ではなく、式です。コンパイラに詳しい人は、この制約に技術的な理由があるかどうかを明確にすることができるかもしれません。
C# 3.0 仕様のセクション 7.5.9 から:
後置インクリメントまたはデクリメント操作のオペランドは、変数、プロパティ アクセス、またはインデクサー アクセスとして分類される式である必要があります。演算の結果は、オペランドと同じ型の値です。後置インクリメントまたはデクリメント操作のオペランドがプロパティまたはインデクサー アクセスである場合、プロパティまたはインデクサーには get アクセサーと set アクセサーの両方が必要です。そうでない場合、コンパイル時エラーが発生します。
さらに、ポスト インクリメント式 ( i++
) は、プレインクリメント ( ++i
) 演算子よりも優先順位が高いため、最初に評価されます。