27

次の2つのC#コードスニペットは、異なる結果を生成します(再帰呼び出しの前後の両方で変数レベルが使用されると想定しています)。なんで?

public DoStuff(int level)
{
  // ...
  DoStuff(level++);
  // ...
}

public DoStuff(int level)
{
  // ...
  DoStuff(level+1);
  // ...
}

以下の回答のいくつかを読んだ後、この問題を欺く方法を強調するために、level ++、++ level、およびlevel+1のスタックトレースを投稿する価値があると思いました。

この投稿のためにそれらを簡略化しました。再帰呼び出しシーケンスはDoStuff(1)で始まります。

//レベル++

DoStuff(int level = 1)
DoStuff(int level = 2)
DoStuff(int level = 2)
DoStuff(int level = 2)

//++レベル

DoStuff(int level = 4)
DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)

//レベル+1

DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)
DoStuff(int level = 1)
4

15 に答える 15

44

他のすべての応答を明確にするには:

+++++++++++++++++++++

DoStuff(a++);

以下と同等です。

DoStuff(a);
a = a + 1;

+++++++++++++++++++++

DoStuff(++a);

以下と同等です。

a = a + 1;
DoStuff(a);

+++++++++++++++++++++

DoStuff(a + 1);

以下と同等です。

b = a + 1;
DoStuff(b);

+++++++++++++++++++++

于 2008-09-22T12:08:36.543 に答える
29

最初の例は実際には次と同等であるため:

public DoStuff(int level)
{  
  // ...
  int temp = level;
  level = level + 1;
  DoStuff(temp);
  // ...
}

++levelと書くこともできることに注意してください。これは次のようになります。

public DoStuff(int level)
{  
  // ...
  level = level + 1;
  DoStuff(level);
  // ...
}

私の意見では、++演算子と--演算子を使いすぎないようにするのが最善です。実際に何が起こっているのかがすぐに混乱したり未定義になったりします。最近のC++コンパイラは、これらの演算子を使用してより効率的なコードを生成しません。

于 2008-09-22T12:00:51.197 に答える
27

level ++はレベルDoStuffに渡し、関数の残りの部分で使用するためにレベルをインクリメントします。再帰が終了することはないため、これはかなり厄介なバグである可能性があります(表示されている内容から、DoStuffには常に同じ値が渡されます)。おそらく++levelが代わりに意味されます。これは、level ++の反対です(レベルをインクリメントし、インクリメントされた値をDoStuffに渡します)?

level + 1は、 level + 1DoStuffに渡し、関数の残りの部分ではレベルを変更しないままにします。

于 2008-09-22T11:58:07.927 に答える
12

の戻り値はlevel++になりlevel、 にtherefore渡さlevelDoStuffます。これは、再帰が決して終了しないため、かなり厄介なバグである可能性があります (表示されているものDoStuffは常に同じ値で渡されます)。おそらく++level、またはlevel + 1代わりに意味されていますか?

level + 1関数の残りの部分では変更されずに渡さlevel + 1れます。DoStufflevel


ポストインクリメント演算子 (variable++) は、関数と正確に同等です

int post_increment(ref int value)
{
    int temp = value;
    value = value + 1
    return temp;
}

プレインクリメント演算子 (++変数) は、関数と正確に同等です。

int pre_increment(ref int value)
{
    value = value + 1;
    return value;
}

したがって、演算子インラインをコードに展開すると、演算子は次と同等になります。

DoStuff(a + 1)

int temp = a + 1;
DoStuff(temp);

DoStuff(++a)

a = a + 1;
DoStuff(a);

DoStuff(a++);

int temp = a;
a = a + 1;
DoStuff(temp);

post-increment は次のものと同等ではないことに注意することが重要です。

DoStuff(a);
a = a + 1;

さらに、スタイルのポイントとして、インクリメントされた値を使用することが意図されていない限り、値をインクリメントすべきではありません (ルールの特定のバージョンでは、「その値を使用する予定がない限り、変数に値を割り当てないでください」 )。値i + 1が二度と使用されない場合、推奨される使用方法はDoStuff(i + 1)and notDoStuff(++i)です。

于 2008-09-22T12:08:08.010 に答える
2

1つ目は、レベルの値を使用し、次にそれをインクリメントすることです。

後者は、渡された変数としてlevel+1を使用しています。

于 2008-09-22T11:58:39.593 に答える
1

level++の現在の値を返しlevel、次に増分しますlevel。 まったく変更されlevel+1ませんが、の値で呼び出されます。levelDoStuff(level + 1)

于 2008-09-22T11:59:56.847 に答える
1
public DoStuff(int level)
{

  // DoStuff(level);
  DoStuff(level++);
  // level = level + 1;
  // here, level's value is 1 greater than when it came in
}

実際にはレベルの値を増やします。

public DoStuff(int level)
{
  // int iTmp = level + 1;
  // DoStuff(iTmp);
  DoStuff(level+1);
  // here, level's value hasn't changed
}

実際には level の値をインクリメントしません。

関数呼び出し前は大きな問題ではありませんが、関数呼び出し後は値が異なります。

于 2008-09-22T12:11:16.863 に答える
1

level++ では、後置演算子を使用しています。この演算子は、変数が使用された後に機能します。つまり、呼び出された関数のスタックに置かれた後、インクリメントされます。一方、レベル + 1 は単純な数式であり、評価され、結果が呼び出された関数に渡されます。最初に変数をインクリメントしてから、呼び出された関数に渡したい場合は、前置演算子を使用できます: ++level

于 2008-09-22T13:05:45.953 に答える
0

最初のコードスニペットは操作後のインクリメント演算子を使用しているため、呼び出しはDoStuff(level);として行われます。ここでインクリメント演算子を使用する場合は、DoStuff(++ level);を使用します。

于 2008-09-22T11:58:51.620 に答える
0

level + 1は、level+1が関数に送信されます。level ++は関数にレベルを送信し、それをインクリメントします。

あなたは++レベルを行うことができ、それはおそらくあなたが望む結果を与えるでしょう。

于 2008-09-22T12:02:38.523 に答える
0

最初の例では、「index」の値を使用し、値をインクリメントして「index」を更新します

2番目の例では、「index」に1を加えた値を使用しますが、「index」の内容は変更しません。

ですから、ここで何をしたいのかによっては、サプライズが発生する可能性があります。

于 2008-09-22T12:02:49.177 に答える
0

最も簡単に言えば、++varは前置演算子であり、残りの式が評価される前に変数をインクリメントします。var++後置演算子は、式の残りの部分が評価された後に変数をインクリメントします。もちろん、他の人が言及したように、で開始され、でインクリメントvar+1される一時変数(メモリ内に個別)を作成します。var1

于 2012-09-14T21:46:26.660 に答える
0

次のように書き直すのは魅力的ですが、

DoStuff(++level);

個人的には、これはメソッド呼び出しの前に変数をインクリメントするよりも読みにくいと思います。上記のいくつかの回答で指摘されているように、次のことがより明確になります。

level++;
DoStuff(level);
于 2008-09-22T12:13:31.460 に答える
0

演算子のオーバーロードを許可する言語を使用し、'+ <integer>' が後置および接頭辞 '++' 以外のことを行うように定義されている場合。

繰り返しになりますが、私は学校のプロジェクト*でそのような忌まわしきものを見たことがあります*。実際に遭遇した場合、おそらく非常に適切で、十分に文書化された理由があります.

[* 私が間違っていなければ、整数のスタック。'++' と '--' はプッシュおよびポップされ、'+' と '-' は通常の演算を実行します]

于 2008-09-22T12:49:42.670 に答える
-2

私の経験では、パラメータ式が最初に評価され、レベルの値を取得します。コンパイラは、式をパラメータとして使用しているかどうかを気にしないため、変数自体は関数が呼び出される前にインクリメントされます...知っているのは、値をインクリメントし、結果として古い値を取得する必要があることだけです。表現。

しかし、私の意見では、このようなコードは本当にずさんです。賢くしようとすると、実際に何が起こっているのかを2度考えなければならないからです。

于 2008-09-22T12:05:08.673 に答える