【问题标题】:Why is there a prefix/postfix ++ but no prefix/postfix +=?为什么有前缀/后缀 ++ 而没有前缀/后缀 +=?
【发布时间】:2011-01-08 23:37:19
【问题描述】:

这似乎是一个愚蠢的问题,但为什么在许多语言中存在++-- 运算符的前缀和后缀版本,但没有类似@987654323 等其他运算符的前缀/后缀版本@ 或 -=?例如,如果我可以编写这段代码:

myArray[x++] = 137; // Write 137 to array index at x, then increment x

我应该能写出类似的东西

myArray[5 =+ x] = 137; // Write 137 to array index at x, then add five to x

当然,这样的运营商是不存在的。是否有一个原因?在 C/C++/Java 中,这似乎是一种奇怪的不对称。

【问题讨论】:

  • 所以,基本上,你问为什么只允许±1的特殊情况?
  • 就个人而言,我赞成myArray[x++++++++++++++++++++] = 137; 语法。
  • @pst 或者myArray[x.plusPlus(10)] = 137;怎么样
  • @templatetypedef :我认为,这看起来更好>> myArray[x=+5] = 137;(添加后)......和现有的>> myArray[x+=5] = 137;(预添加)......这个想法是,保持x 始终在左侧!
  • 应该将x=-1 解析为x =- 1 还是x = -1? :)

标签: java c++ c operators


【解决方案1】:

我猜有几个原因,我认为权重较大的可能是:

  • 可能没有被认为有太多实际用例(早期的一些语言设计者甚至可能没有想到)
  • 前/后增量直接映射到机器操作(至少在几台机器上),因此他们找到了进入语言的方式(更新:事实证明这并不完全正确,即使在计算中通常是这样认为的传说。见下文)。

再一次,虽然 pre/post/increment/decrement 运算符的想法可能受到了机器操作的影响,但看起来它们并没有被专门放入语言中以利用这些。以下是丹尼斯·里奇对他们的评价:

http://cm.bell-labs.com/cm/cs/who/dmr/chist.html

Thompson 更进一步发明了 ++ 和 -- 运算符,它们可以递增或递减;它们的前缀或后缀位置决定了更改是发生在记下操作数的值之前还是之后。它们不在 B 的最早版本中,而是沿途出现。人们经常猜测,它们被创建为使用由 C 和 Unix 首次流行的 DEC PDP-11 提供的自动递增和自动递减地址模式。这在历史上是不可能的,因为在开发 B 时没有 PDP-11。然而,PDP-7 确实有一些“自动递增”内存单元,其特性是通过它们的间接内存引用会增加单元。此功能可能向 Thompson 建议了此类运算符;使它们同时具有前缀和后缀的概括是他自己的。事实上,自增单元并没有直接用于算子的实现,而更强烈的创新动机可能是他观察到 ++x 的平移小于 x=x+1 的平移。

【讨论】:

    【解决方案2】:

    只要y没有副作用:

    #define POSTADD(x,y) (((x)+=(y))-(y))
    

    【讨论】:

    • 或者在 C++ 中有一些副作用安全性:template <typename T, typename U> T postadd( T& x, U increment) { T tmp = x; x = x + increment; return tmp; } 但我强烈建议避免使用这样的东西(如果有充分的理由使用它,我想听听理由 - 这可能很有趣)。
    【解决方案3】:

    我会做一个假设。 ++i/i++ 有很多用例,并且在许多特定类型的增量(前/后)中有所不同。我不知道我见过多少次像while (buf[i++]) {...} 这样的代码。另一方面,+= 的使用频率要低得多,因为一次将指针移动 5 个元素几乎没有意义。

    因此,在 += 的后缀版本和前缀版本之间的差异很重要的应用中,没有足够常见的应用程序。

    【讨论】:

      【解决方案4】:

      我猜是因为它太神秘了。 一些人认为,即使是 ++/-- 也应该避免,因为它们会引起混淆,并且是造成大多数缓冲区溢出错误的原因。

      【讨论】:

      • 我只在 for 循环中使用后缀 ++(并且不经常使用 --)。
      • @Goran:这对 C 来说很棒,但对 C++ 来说就不是很好了(迭代器上的后缀操作可能非常昂贵)。
      • “有些人认为即使是 ++/-- 也应该避免,因为它们会引起混乱,并且是造成大多数缓冲区溢出错误的原因。”:我不认同这个论点。不是++--,是没注意缓冲区的长度。如果您不注意缓冲区的长度,+= 将无法帮助您避免缓冲区溢出。
      • @Max Lybbert:我认为这些论点试图说明 for (; n > 0; --n) *dst++ = *src++;不是一种应该使用的风格。
      • 有很多事情要避免,但这并不能说明++-- 的优点。我的 The C Programming Language 副本经过大量努力解释了为什么 (*src++ = *dest++) ; 复制以 null 结尾的字符串(并声称任何 C 程序员都应该理解它,即使他们不使用那种风格)。如果dstsrc 的长度至少为n,则给出的示例可以正常工作。只有当程序员不注意缓冲区的长度时它才会失败,并且切换到+=-= 不会使代码变得更好。
      【解决方案5】:

      因为 -- 和 ++ 运算符映射到 CPU 中的 inc(rement) 和 dec(rement) 指令(除了加减法),而这些运算符是假定的 映射到指令,因此它们作为单独的运算符存在。

      【讨论】:

      • 但这仅适用于一种处理器架构,对吧?例如,我不记得在 MIPS 的任何地方看到过这个。
      • 是的,对某些人来说确实如此,我所知道的就是 x86。
      • @templatetypedef:PDP-11 比 MIPS 稍早一点,而 C 最初是为与 PDP-11 一起工作而编写的。其他人都有前后递增和递减运算符,因为 C 有它们。
      【解决方案6】:

      Java 和 C++ 有前后递增和递减运算符,因为 C 有它们。 C 有它们,因为 C 主要是为 PDP-11 编写的,而 PDP-11 有 INCDEC 指令。

      在过去,优化编译器并不存在,所以如果你想使用单循环增量运算符,要么为它编写汇编程序,要么你的语言需要一个显式运算符; C 是一种可移植的汇编语言,具有显式的递增和递减运算符。此外,++ii++ 之间的性能差异现在很少重要,但在 1972 年确实很重要。

      请记住,C 已经快 40 岁了。

      【讨论】:

      • 然而,数量惊人的 SO/web 问题似乎仍然与 i++++ii = i + 1 的“性能”有关 ... :-/
      【解决方案7】:

      如果我不得不猜测,通常等同于:

      x += 5;

      ...与:

      x = x + 5;

      出于显而易见的原因,这样写是荒谬的:

      x + 5 = x;

      我不确定您将如何仅使用 + 运算符来模仿 5 =+ x 的行为。顺便说一句,嗨 htiek!

      【讨论】:

      • 显然这是可能的。在x + 5 = x 的情况下,可以证明5 = 0 从两边减去x。 QED。 ;-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-30
      • 2014-04-28
      相关资源
      最近更新 更多