代码之家  ›  专栏  ›  技术社区  ›  Dlaor

我++和我的区别是什么?[复制品]

c#
  •  182
  • Dlaor  · 技术社区  · 15 年前

    这个问题已经有了答案:

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

    6 回复  |  直到 8 年前
        1
  •  169
  •   LarsTech    12 年前

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


    i++ 意思是“告诉我 i ,然后递增'

    ++i 表示“增量” ,然后告诉我值'


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

        2
  •  400
  •   Community CDub    8 年前

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

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

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

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

    对于前缀形式:

    1. x被计算为产生变量
    2. 变量的值被复制到临时位置
    3. 临时值递增以生成新值(不覆盖临时值!)
    4. 新值存储在变量中
    5. 操作的结果是 新价值 (即临时工的增量值)

    对于后缀表单:

    1. x被计算为产生变量
    2. 变量的值被复制到临时位置
    3. 临时值递增以生成新值(不覆盖临时值!)
    4. 新值存储在变量中
    5. 操作的结果是 临时工的价值

    需要注意的一些事项:

    第一, 两种情况下事件的时间顺序完全相同 . 再说一遍,绝对是 在这种情况下, 事件的时间顺序 前缀和后缀之间的更改。说评估发生在其他评估之前或之后是完全错误的。评估发生在 完全一样的顺序 在这两种情况下,您可以通过步骤1到4看到相同。这个 只有 区别在于 最后一步 -结果是临时值还是新的递增值。

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

    public class Application
    {
        public static int currentValue = 0;
    
        public static void Main()
        {
            Console.WriteLine("Test 1: ++x");
            (++currentValue).TestMethod();
    
            Console.WriteLine("\nTest 2: x++");
            (currentValue++).TestMethod();
    
            Console.WriteLine("\nTest 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);
        }
    }
    

    以下是结果…

    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() 扩展名按预期显示相同的值。

    然而,在第二种情况下,人们会试图告诉你 当前价值 发生 之后 呼唤 测试方法() 但是正如你从结果中看到的那样 之前 “当前:2”结果指示的调用。

    在这种情况下,首先 当前价值 存储在临时文件中。接下来,该值的递增版本将存储回 当前价值 但不触及仍保存原值的临时物品。最后,临时的 测试方法() . 如果增量发生 之后 呼唤 测试方法() 然后,它会写出相同的、非递增的值两次,但不会。

    需要注意的是,从 currentValue++ ++currentValue 操作基于临时值,而不是两个操作退出时存储在变量中的实际值。

    按照上面的操作顺序调用,前两步将变量的当前值复制到临时变量中。这是用来计算返回值的;对于前缀版本,它是临时值递增,而对于后缀版本,它是直接/不递增的值。变量本身不会在初始存储后重新读取到临时文件中。

    更简单地说,postfix版本返回从变量读取的值(即临时值),而prefix版本返回回变量的值(即临时值的增量)。两者都不返回变量的值。

    理解这一点很重要,因为变量本身可能是不稳定的,并且在另一个线程上发生了变化,这意味着这些操作的返回值可能与存储在变量中的当前值不同。

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

    http://blogs.msdn.com/b/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx

    这就引出了这样一个问题:

    int[] arr={0}; int value = arr[arr[0]++]; Value = 1?

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

    http://blogs.msdn.com/b/ericlippert/archive/2008/05/23/precedence-vs-associativity-vs-order.aspx

    http://blogs.msdn.com/b/ericlippert/archive/2007/08/14/c-and-the-pit-of-despair.aspx

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

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

    此外,在考虑其他具有副作用的操作时,我们也遇到了类似的微妙问题,例如链接的简单分配:

    http://blogs.msdn.com/b/ericlippert/archive/2010/02/11/chaining-simple-assignments-is-not-so-simple.aspx

    下面是一篇有趣的文章,讨论为什么增量运算符会导致 价值观 C而不是 变量 :

    Why can't I do ++i++ in C-like languages?

        3
  •  20
  •   dcp    15 年前

    如果你有:

    int i = 10;
    int x = ++i;
    

    然后 x 11 .

    但如果你有:

    int i = 10;
    int x = i++;
    

    然后 X 10 .

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

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

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

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

    ++x;
    

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

        4
  •  5
  •   Himanshu THE ONLY ONE    11 年前
    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.
    

    这能回答你的问题吗?

        5
  •  5
  •   AGuyCalledGerald Omid.Hanjani    8 年前

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

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

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

    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循环或类似的循环中。这些循环是相同的:

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

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

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

    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);
    

    等等。

        6
  •  4
  •   DevinEllingson    15 年前

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