关于c#:i ++和++ i有什么区别?


What is the difference between i++ and ++i?

本问题已经有最佳答案,请猛点这里访问。

我看到它们都被用于许多C代码中,我想知道何时使用i++++i(i是一个数字变量,如intfloatdouble等)。有人知道吗?


不幸的是,这个问题的典型答案已经在这里发布了,一个在剩余操作之前执行增量操作,另一个在剩余操作之后执行增量操作。尽管这一观点直观地得到了理解,但这种说法表面上是完全错误的。事件的时间顺序在C中定义得非常好,而且强调的是,与其他操作相比,前缀和后缀版本所做的事情顺序不同。好的。

毫无疑问,你会看到这个问题的很多错误答案。很多"自学C"的书也会弄错。而且,C做的方式与C做的方式不同。许多人认为C和C是同一种语言,但事实并非如此。在我看来,C中的递增和递减操作符的设计避免了C中这些操作符的设计缺陷。好的。

必须回答两个问题才能确定前缀和后缀+在C中的具体操作。第一个问题是结果如何?第二个问题是,增量的副作用何时发生?好的。

这两个问题的答案都不明显,但事实上,一旦你看到它,就相当简单了。让我为您详细说明X++和X++对变量X的作用。好的。

对于前缀形式:好的。

  • x被计算为产生变量
  • 变量的值被复制到临时位置
  • 临时值递增以生成新值(不覆盖临时值!)
  • 新值存储在变量中
  • 操作的结果是新值(即临时值的递增值)
  • 对于后缀表单:好的。

  • x被计算为产生变量
  • 变量的值被复制到临时位置
  • 临时值递增以生成新值(不覆盖临时值!)
  • 新值存储在变量中
  • 操作的结果是临时
  • 需要注意的一些事项:好的。

    首先,两种情况下事件的时间顺序完全相同。同样,事件在时间上的顺序在前缀和后缀之间变化的情况绝对不是这样。说评估发生在其他评估之前或之后是完全错误的。在这两种情况下,评估的顺序完全相同,正如您在步骤1到4中看到的一样。唯一的区别是最后一步——结果是临时值还是新的递增值。好的。

    您可以通过一个简单的C控制台应用程序轻松地演示这一点:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Application
    {
        public static int currentValue = 0;

        public static void Main()
        {
            Console.WriteLine("Test 1: ++x");
            (++currentValue).TestMethod();

            Console.WriteLine("
    Test 2: x++"
    );
            (currentValue++).TestMethod();

            Console.WriteLine("
    Test 3: ++x"
    );
            (++currentValue).TestMethod();

            Console.ReadKey();
        }
    }

    public static class ExtensionMethods
    {
        public static void TestMethod(this int passedInValue)
        {
            Console.WriteLine("Current:{0} Passed-in:{1}",
                Application.currentValue,
                passedInValue);
        }
    }

    以下是结果…好的。

    1
    2
    3
    4
    5
    6
    7
    8
    Test 1: ++x
    Current:1 Passed-in:1

    Test 2: x++
    Current:2 Passed-in:1

    Test 3: ++x
    Current:3 Passed-in:3

    在第一个测试中,您可以看到currentValue和传入TestMethod()扩展的值与预期值相同。好的。

    但是,在第二种情况下,人们会试图告诉您,currentValue的增量发生在调用TestMethod()之后,但从结果中可以看出,它发生在调用之前,如"current:2"结果所示。好的。

    在这种情况下,首先将EDOCX1的值(0)存储在临时文件中。接下来,该值的递增版本存储回currentValue,但不接触仍然存储原始值的临时值。最后,临时文件被转交给TestMethod()。如果增量发生在调用TestMethod()之后,那么它将写出相同的非增量值两次,但不会。好的。

    It's important to note that the value returned from both the currentValue++ and ++currentValue operations are based on the temporary and not the actual value stored in the variable at the time either operation exits.

    Ok.

    Recall in the order of operations above, the first two steps copy the then-current value of the variable into the temporary. That is what's used to calculate the return value; in the case of the prefix version, it's that temporary value incremented while in the case of the suffix version, it's that value directly/non-incremented. The variable itself is not read again after the initial storage into the temporary.

    Ok.

    Put more simply, the postfix version returns the value that was read from the variable (i.e. the value of the temporary) while the prefix version returns the value that was written back to the variable (i.e. the incremented value of the temporary). Neither return the variable's value.

    Ok.

    This is important to understand because the variable itself could be volatile and have changed on another thread which means the return value of those operations could differ from the current value stored in the variable.

    Ok.

    令人惊讶的是,人们常常对优先级、关联性和副作用的执行顺序感到非常困惑,我怀疑主要是因为C.C.中的混乱被精心设计成在所有这些方面都不那么混乱。对于这些问题的一些额外分析,包括我进一步证明了前缀和后缀操作"及时移动内容"的观点是错误的,请参见:好的。

    http://blogs.msdn.com/b/ericlippet/archive/2009/08/10/precedence-vs-order-redux.aspx好的。

    这就引出了这样一个问题:好的。

    int[]arr=0 int value=arr[arr[0]++];value=1?好的。

    你也可能对我之前关于这个主题的文章感兴趣:好的。

    http://blogs.msdn.com/b/ericlippet/archive/2008/05/23/precedence-vs-associative-vs-order.aspx好的。

    和好的。

    http://blogs.msdn.com/b/ericlippet/archive/2007/08/14/c-and-the-pit-of-deadise.aspx好的。

    还有一个有趣的例子,C使得很难解释正确性:好的。

    blogs.msdn.com http:/ / / / / B ericlippert archive/2005/04/28/bad-recursion-revisited.aspx>

    我们也遇见类似问题,subtle when that have other操作considering such as chained单端效应,assignments:>

    blogs.msdn.com http:/ / / / / / ericlippert B馆2010年chaining-simple-assignments-is-not-so-simple.aspx/02/11/>

    后安布尔是由运营商的兴趣为什么the result中增量值比在C # Rather变量:>

    为什么不给你的C + +类的语言吗?>

    好吧。


    奇怪的是,其他两个答案似乎没有拼出来,绝对值得说:

    i++的意思是"告诉我i的值,然后递增"

    ++i表示‘递增i,然后告诉我值’

    它们是预增量、后增量运算符。在这两种情况下,变量都是递增的,但是如果您在完全相同的情况下获取这两个表达式的值,结果将不同。


    如果你有:

    1
    2
    int i = 10;
    int x = ++i;

    那么,x将是11

    但如果你有:

    1
    2
    int i = 10;
    int x = i++;

    那么,x就是10

    请注意,正如Eric指出的,在这两种情况下,增量是同时发生的,但结果不同的是给出的值(谢谢Eric!).

    一般来说,我喜欢使用++i,除非有充分的理由不这样做。例如,在编写循环时,我喜欢使用:

    1
    2
    for (int i = 0; i < 10; ++i) {
    }

    或者,如果我只需要增加一个变量,我喜欢使用:

    1
    ++x;

    通常情况下,一种方法或另一种方法没有太大的意义,可以归结为编码样式,但是如果您在其他分配中使用运算符(如在我的原始示例中),则必须注意潜在的副作用。


    运算符的工作方式是同时递增,但如果它在变量之前,则表达式将使用递增/递减的变量进行计算:

    1
    2
    int x = 0;   //x is 0
    int y = ++x; //x is 1 and y is 1

    如果它在变量之后,则当前语句将使用原始变量执行,就好像它尚未递增/递减:

    1
    2
    int x = 0;   //x is 0
    int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0

    除非必要,我同意DCP使用预增/减(++X)。实际上,我唯一一次使用后递增/递减是在while循环或类似的循环中。这些循环是相同的:

    1
    2
    3
    4
    5
    while (x < 5)  //evaluates conditional statement
    {
        //some code
        ++x;       //increments x
    }

    1
    2
    3
    4
    while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
    {
        //some code
    }

    您还可以在索引数组等时执行此操作:

    1
    2
    3
    4
    5
    int i = 0;
    int[] MyArray = new int[2];
    MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
    MyArray[i] = 5678;   //sets array at index 1 to '5678'
    int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);

    等等。


    1
    2
    3
    int i = 0;
    Console.WriteLine(i++); // Prints 0. Then value of"i" becomes 1.
    Console.WriteLine(--i); // Value of"i" becomes 0. Then prints 0.

    这能回答你的问题吗?


    就记录而言,在C++中,如果你可以使用(即)你不关心操作的顺序(你只想增加或减量并在以后使用它),前缀操作符是更高效的,因为它不必创建对象的临时副本。不幸的是,大多数人使用posfix(var++)而不是前缀(++var),这是我们最初学到的。(我在一次采访中被问及此事)。不确定这在C中是否正确,但我想应该是。