【问题标题】:whether a language needs preIncrement (++x) and postIncrement (x++)语言是否需要 preIncrement (++x) 和 postIncrement (x++)
【发布时间】:2011-01-31 13:51:06
【问题描述】:

我从未在实际代码中看到 pre-incrementpost-increment 的用例。我最常看到它们的唯一地方是谜题。
我的观点是,它带来了更多的混乱而不是有用。

  • 是否有任何实际的用例场景
  • 这不能通过使用 += 来完成

    y = x++

    y = x
    x += 1

【问题讨论】:

  • 有必要吗?我没有必要喝自己的尿液,但它是无菌的,我喜欢它的味道。 - 补丁 O'Houlihan
  • 您是一名计算机科学工程专业的学生,​​您对 x++ 和 ++x 之间的区别感到困惑?而你从来没有发现用不同的方式表达相似的事情很有用?
  • 言归正传:尽管我认为提问者是“错误的”,但我更加坚信这是一个真实的问题。

标签: programming-languages increment post-increment pre-increment


【解决方案1】:

这只是写同一件事的一种更短的方式,只会让那些不深入了解 C (a) 的人感到困惑。替换也可以提出相同的论点:

for (i = 0; i < 10; i++)
    printf ("%d\n", i);

与:

i = 0;
while (i < 10) {
    printf ("%d\n", i);
    i = i + 1;
}

因为任何for 也可以用while 完成,或者:

i = 0;
loop: if (i < 10) {
    printf ("%d\n", i);
    i = i + 1;
    goto loop;
}

因为 any 循环构造可以由条件和goto 构建。但是(我希望)你不会那样做,对吗?


(a)我有时喜欢将这一点解释为简单的陈述和副作用,这样可以让 C 代码更简洁,通常不会或几乎不损失可读性。

对于声明:

y = x++;

语句x 分配给y,其副作用是x 之后会递增。 ++x也一样,只是副作用是提前发生的。

同样,赋值的副作用是它的计算结果是赋值,这意味着您可以执行以下操作:

while ((c = getchar()) != -1) count++;

这使得事情像:

42;

完全有效但无用的 C 语句。

【讨论】:

  • 为什么不for (i = 0; i &lt; 10; i+=1)
  • void strcpy(char* a, char* b) { while (*a++ = *b++) ; }
  • @Ananantha,你没有抓住重点。我要说的是,对于那种特殊情况,你会使用“for”而不是“while”(在这种情况下,i++/i+=1 的区别是无关紧要的)。底线:使用您可以使用的语言功能。了解他们。
  • 啊,Java(或至少我的 IDE)在您编写最后一条语句时开始抱怨:它报告错误消息 Not a statement
  • @MC,Java 比 C 更严格一些。
【解决方案2】:

如果您从历史的角度和构思它们的时间来考虑它们,那么前置和后置增量运算符会更有意义。

在 C 基本上是 PDP-11 机器的高级汇编程序&lt;/flamebait&gt; 的日子里,早在我们拥有现在拥有的良好优化编译器之前,就有一些常见的习惯用法,即后自增运算符是非常适合。像这样的事情:

char* strcpy(char* src, char* dest)
{
  /* highly simplified version and likely not compileable as-is */
  while (*dest++ = *src++);
  return dest;
}

有问题的代码生成的 PDP-11(或其他)机器语言代码大量使用了底层寻址模式(如相对直接和相对间接),这些寻址模式恰好结合了这些类型的前后递增和递减操作.

所以回答你的问题:现在语言“需要”这些吗?不,当然不。可以证明,就计算事物而言,您需要非常少。如果您问“这些功能是否可取?”,这个问题会更有趣。对此,我会回答一个合格的“是”。

使用你的例子:

y = x;
x += 1;

对比

y = x++;

我可以立即看到两个优势。

  1. 代码更简洁。为了理解你在做什么,我需要知道的一切都在一个地方(只要我知道语言,自然!)而不是分散开来。跨两条线“展开”似乎是一件很挑剔的事情,但如果你要做成千上万条,最终会产生很大的不同。
  2. 在第二种情况下,即使是由蹩脚的编译器生成的代码也更有可能是原子的。在第一种情况下,除非你有一个好的编译器,否则它很可能不会。 (并非所有平台都有良好、强大的优化编译器。)

另外,我发现你在谈论 += 非常有说服力,而这本身就是一种“不需要”的说法 x = x + 1;.... 毕竟我无法想到任何用例场景+= 不能由 _ = _ + _ 代替。

【讨论】:

  • +1 表示历史级别,但我不确定那是火焰诱饵,它真的是 一个高级汇编程序(虽然不确定它是 PDP8 还是 PDP11)。你的最后一段也是一个很好的观点。
  • 好答案,但我认为一元运算符的语义与二元运算符的语义有很大的不同。
  • 使用像x[f(y)][g(z)] += 10这样的代码实际上可能比x[f(y)][g(z)] = x[f(y)][g(z)] + 10更有效,因为编译器只需要在第一种情况下评估x[f(y)][g(z)]一次,但在第二种情况下可能两次。
  • @gabe:绝对正确。在像 C 这样的语言中,x[f(y)][g(z)] 将在运行时评估一次并返回一个左值,可以评估并分配其引用,而无需进行第二次评估。如果 fg 是不纯函数,这可能会导致您建议的两种形式之间的行为不同。哎呀!
  • @cHao,我理解你关于“理智”代码的说法,但需要明确的是,C++ 能够改变这样的习语(这就是通过为a+=ba=a+b) 不是“加号”,我不在乎哪个类实现了它。它违背了语言的基本原则(由于内置的​​算术类型已经很好理解),并且会破坏阅读代码的模式识别。 C++ 爱好者无疑会对此表示反对,但 IMO 会因为“可以做”和“应该做”编程之间的混淆而反对。在 C++ 中太常见了。
【解决方案3】:

您在这里无意中提出了一个更大的问题,随着时间的流逝(几十年),这个问题会让您越来越了解它。

语言经常犯错误,在不应该提供“能力”的情况下提供。 IMO, ++ 应该是一个独立的语句only,绝对不是表达式运算符。

尽量谨记以下几点:我们的目标不是编写代码供有能力的工程师阅读。目标是编写代码,让有能力的工程师在凌晨 3 点筋疲力尽并开始喝咖啡时阅读。

如果工程师对您说“所有代码构造都会给您带来麻烦。您只需要知道自己在做什么。”然后笑着走开,因为他只是将自己暴露为问题的一部分。

换句话说,请永远不要编写这样的代码:

a[aIndex++] = b[++bIndex];

您可以在此处找到有关此类事情的有趣对话: Why avoid increment ("++") and decrement ("--") operators in JavaScript?

【讨论】:

    猜你喜欢
    • 2014-10-24
    • 2013-07-05
    • 2014-06-02
    • 2019-05-10
    • 1970-01-01
    • 2012-05-28
    • 2019-01-22
    • 2023-03-11
    • 2020-06-17
    相关资源
    最近更新 更多