14

現在、私は C++ プログラマーのクラスに C# 言語の基礎を教えています。トピック演算子について説明したとき、私は主、単項などの演算子の C# 標準カテゴリを使用しました。

出席者の 1 人は戸惑いました。C# 標準では、「接頭辞 ++/--」ではなく、「接尾辞 ++/--」が主要な演算子のカテゴリに入れられたためです。この混乱の背後にある彼女の理論的根拠は、演算子「接頭辞 ++/--」に関して C++ 演算子「接尾辞 ++/--」を実装したいというものでした。言い換えれば、彼女は演算子「接頭辞 ++/--」を主要な演算子として数えたいと考えています。- 彼女の主張は理解できるが、その背後にある論理的根拠を彼女に与えることはできない. OK 演算子「接尾辞 ++/--」は「接頭辞 ++/--」よりも優先順位が高いですが、これがその背後にある唯一の根拠ですか?

仕様では、セクション「14.2.1 演算子の優先順位と結合性」で言及されています。

だから私の非常に中立的な質問: Postfix ++/-- が C# の主要な演算子として分類されるのはなぜですか? そこにはもっと深い真実がありますか?

4

3 に答える 3

2

ECMA標準自体は、「プライマリ」演算子が何であるかを定義していないため、優先順位(つまり、「単項」の前に来る)以外に、他の重要性はありません。言葉の選択はおそらく悪かった。

多くのCリンク言語では、接尾辞演算子は式の中間結果が格納される一時変数を作成する傾向があることを考慮してください(セミコロンの「接尾辞よりも接頭辞演算子を優先する」を参照)。したがって、プレフィックスバージョンとは根本的に異なります。

それでも、MonoとVisual Studioが接尾辞とプレフィックス形式を使用してforループをコンパイルする方法をすばやく確認したところ、生成されたILコードは同じであることがわかりました。postfix / prefix式の値を使用する場合にのみ、少なくとも言及されている実装では、異なるILに変換されます(「dup」命令が配置されている場所にのみ影響します)。

于 2011-08-13T13:19:09.747 に答える
2

編集:さて、家に帰ってきました。紛らわしい部分のほとんどを削除しました...

x++が一次表現に分類される理由はわかりませんが、そうで++xはありません。私はそれがあなたが書くコードに関して大きな違いをもたらすとは思わない. 同上優先。より一般的に使用されているため、接尾辞がプライマリと見なされるのだろうか? ちなみに、注釈付きの C# 仕様には、ECMA エディションでも Microsoft C# 4 エディションでも、これに関する注釈はありません。(確認する C# 3 エディションがすぐに見つかりません。)

ただし、実装に関しては、++前置式と後置式の両方で使用される一種の疑似演算子と考えることができます。特に、++演算子をオーバーロードすると、そのオーバーロードが後置インクリメントと前置インクリメントの両方に使用されます。stakx がコメントで指摘したように、これは C++ とは異なります。

注意すべきことの 1 つは、ポスト インクリメント/ポスト デクリメント式にはオペランドとして一次式が必要であるのに対し、プレインクリメント/プレデクリメント式にはオペランドとして単項式のみが必要であるということです。どちらの場合も、オペランドは変数、プロパティ アクセス、またはインデクサー アクセスとして分類する必要があるため、実際にどのよう違いが生じるかはわかりません。

EDIT:別のコメントを与えるために、恣意的に見えますが、仕様に次のように記載されていると奇妙に見えることに同意します。

一次式には、最も単純な形式の式が含まれます

ただし、プレインクリメントのステップのリストは、ポストインクリメントのステップのリストよりも短く/単純です (「値を保存する」ステップが含まれていないため)。

于 2011-08-13T08:37:21.220 に答える
1

違いは、a[i++]がインデックス付きの要素iにアクセスすることです。

a [++ i]は、i+1のインデックスが付けられた要素にアクセスします。

どちらの場合も、a [++ i /i++]の実行後

私はi+1になります。

パラメータの順序を想定できないため、問題が発生する可能性があります

関数(i ++、i ++、i ++)

iを3回インクリメントしますが、順序はわかりません。最初にiが4の場合、function(4,5,6)を持つこともできます

また、function(6,5,4)またはfunction(6,4,5)もあります。

ネイティブ型(「int」など)の例として使用したので、それでも問題はありません。クラスがあると事態はさらに悪化します。

演算子の結果をオーバーロードしても変更されない場合、変更されるのはその優先順位です。これもトラブルの原因になります。

したがって、ある場合には、参照を返す前に「++」が適用され、別の場合には、参照を返す「後に」適用されます。そして、オーバーロードするときは、参照に戻る前に適用する方がおそらく良いでしょう(したがって、少なくともオーバーロードの観点からは、++何かが何か++よりもはるかに優れています)。

オーバーロードされた++を持つジェネリッククラスを取ります(2つのアイテム、fooとbarがあります)

    foo = bar ++; //is like writing (foo=bar).operator++();

    foo = ++bar; // is like writing foo= (bar.operator++());

そして、多くの違いがあります。特に、参照を割り当てずにもっと複雑なことを行う場合、または内部的にオブジェクトに浅いコピーと深いコピーに関係するものがある場合は特にそうです。

于 2012-11-16T14:59:51.477 に答える