我真正意味着什么?

时间:2015-10-12 00:09:13

标签: c#

这个问题已被多次询问,“i ++和++ i之间有什么区别”。在What is the difference between i++ and ++i?接受的答案,我在许多其他地方也看过这种语言,是“i ++意味着'告诉我i的价值,然后增加',而++我的意思是'增量我,然后告诉我价值'。

让我感到困惑的是,我不知道我们正在讨论在 场景中为i取回值。我认为i ++在语法上等同于:

i = i + 1;

这是一个陈述,而不是一个表达,所以我不明白我在哪里被退回。

请您说明声明的实际含义吗?

谢谢,

3 个答案:

答案 0 :(得分:17)

由于我不知道的原因,这个带有公认答案的老问题今天吸引了新的答案,其中许多都包含重大错误或遗漏。让我试着明确地回答问题的问题

  

这个问题已被多次询问," i ++和++ i"之间的区别是什么?在[...]中接受的答案,以及我在许多其他地方也看过这种语言的是," i ++意味着告诉我i的价值,然后增加&#39 ;,而++我的意思是增加i,然后告诉我价值'。

正如我在回答同一个问题时所指出的那样:这种表征是常见的,是理解的第一次理解,但不幸的是,当你更仔细地看待语义时会产生误导。请不要被这种含糊不清且不完全准确的特征所误导。请改为阅读我对该问题的回答。

  

让我感到困惑的是,我不知道在任何一个场景中我们都在讨论为i取回一个值。我认为i++在句法上等同于i = i + 1;这是一个陈述,而不是表达,所以我根本不知道我在哪里被归还。

你在这里有很多误解。而不是全部攻击它们,让我们说出真相是什么。

首先,++ii++ 完全等同 。您不能必然采用包含++ii++的合法程序,并将其仅在语法上转换为其他法律程序。所以只是从头脑中消除这种想法。这些道德等同于increment-and-assign,并且应该语义等价,但是必然一个保留程序的语法desugaring语义或合法性。

现在让我们说一些更真实的事情。但首先,一些警告。出于本讨论的目的,递增表达式i是int类型的变量,可以将其作为变量或没有副作用的值(包括异常)进行求值。而且,我们假设递增操作不会产生异常。而且我们假设一个执行线程。如果你想知道在评估变量可以抛出或产生另一个副作用的情况下增量和赋值的语义,或者不是变量而是属性,或者操作是用户定义的,或者多个线程正在观察或变异变量,详见规范

那就是说,这是一些真实的事实:

  • ++ii++i = i + 1表达式
  • ++i;i++;i = i + 1;陈述
  • ++i的语义如下:

    1. temp1被赋予i
    2. 的值
    3. temp2的值为temp1 + 1
    4. 我被赋予temp2
    5. 的值
    6. 表达式的值是temp2
  • i++的语义如下:

    1. temp1被赋予i
    2. 的值
    3. temp2的值为temp1 + 1
    4. 我被赋予temp2
    5. 的值
    6. 表达式的值为temp1
  • 请注意,两种形式之间的区别是产生的值。 产生副作用的步骤在两种情况下均相同。您在单线程C#中保证,在生成值之前,观察到副作用已完成

  • i = i + 1的语义如下:
    1. temp1被赋予i
    2. 的值
    3. temp2的值为temp1 + 1
    4. 我被赋予temp2
    5. 的值
    6. 表达式的值是temp2
  • 请注意i = i + 1的语义与++i的语义相同。这并不能保证您可以在任意程序中语法上将i = i + 1替换为++i,反之亦然。在某些程序中,这可能是可能的。
  • 请注意i++的语义不允许&#34; easy&#34;语义等价的形式。 ((Func<int, int, int>)((int j, int k)=>j))(i, i=i+1)具有相同的语义,但显然是一个疯狂的输入。

  • 这三种陈述形式的语义是:

    1. 正常评估表达式。
    2. 弃掉结果。

希望这明确地消除了对什么是表达,什么是陈述,表达产生什么副作用和价值以及它们以何种顺序发生的误解。同样,请注意,这种解释仅针对涉及整数变量而对单个线程没有副作用的简单情况。有关这些操作如何在其他类型上工作,或与异常交互或如何在多线程程序中工作的详细信息,请参阅C#规范或询问更具体的问题。

最后:我个人仍然觉得这一切令人困惑,我已经使用C语言后代语言编程了30年,我在C#中实现了这些语义。如果我发现它们令人困惑,并且如果我在这些运算符上看到的每个问题的几乎每个答案都包含重大错误或遗漏,那么我们可以有把握地得出这些令人困惑的运算符的结论。因此,我几乎从未在我的生产代码中使用++--。我认为使用一个对其值和副作用都有用的表达式是不好的风格。

尝试找到一种方法来构造程序,以便任何语句都有一个副作用,而副作用表达式仅限于表达式语句。避免使用++,尤其要避免i++++i具有不同语义的任何情况,因为这会使程序难以理解并因此难以理解保持正确。

答案 1 :(得分:13)

编辑: 请参阅Eric's answer,我的是我。

你是对的。 ++等同于i = i + 1,但需要记住的是i = i + 1不仅是一个语句,还可以用作表达式:

Console.WriteLine((i = i + 1) * 42); // will inc i, and then print i*42
Console.WriteLine(++i * 42); // exactly same

Console.WriteLine(i++ * 42); // will inc i, and print old_i*42
Console.WriteLine((i++) * 42); // exactly same

简而言之:

// this
int j = ++i * 42;
// behaves like
int j = (i = i + 1) * 42;

// but this
int j = i++ * 42;
// actually behaves like
int prev = i;
i = i + 1;
int j = prev * 42;

答案 2 :(得分:0)

我认为你可以考虑以下两个函数来类比i++++i

Fiddle

public static int IPlusPlus(ref int i) {
    // simply increment i before returning it
    i = i + 1;
    return i;
}

public static int PlusPlusI(ref int i) {
    // increment i only after you already returned it
    try {
        return i;
    }
    finally {
        i = i + 1;
    }
}

就像函数调用一样,i++++i右侧表达式,这意味着var a = i++;var a = ++i;是有效的语句。但i++ = 5;++i = 5;无效,因为它会将它们用作左侧表达式。