为啥递增和递减是一元运算
Posted
技术标签:
【中文标题】为啥递增和递减是一元运算【英文标题】:Why increment and decrement are unary operations为什么递增和递减是一元运算 【发布时间】:2015-08-29 09:42:21 【问题描述】:看起来这是一个非常奇怪的问题,因为我已经阅读了很多文档,其中递增和递减是一元运算,没有任何解释。
我可能是错的,但++i
与i+=1
相似(如果没有任何覆盖):
int i = 1;
Console.WriteLine(++i); // 2
int j = 1;
Console.WriteLine(j+=1); // 2
在这种情况下,前置增量是简单的语法糖,用于隐藏二元运算符 plus 和 1
作为第二个参数。
不是吗?
为什么自增和自减是独立的一元运算,难道它不只是二元加运算符,带有预定义的第二个参数,值为1
吗?
【问题讨论】:
它们是一元的,因为只涉及一个操作数:要增加或减少的东西。它是否只是语法糖取决于语言。在 C++ 中,这些运算符可能有不同的语义。 因为它是如此常见的操作,人们懒得省略第二个操作数。请注意++i
和i++
之间存在差异,因此它通常允许更短的代码。
好问题。太糟糕了,这不是一个编程问题!
另一个原因可能是用于原始 C 编译器的 PDP 计算机具有自动递增和自动递减寻址模式,使得 i++
在某些情况下是免费的。例如,使用 i += 2
需要单独的指令。
注意:对于用户类型,在 C++ 中,++x
和 x+=1
可能调用不同的函数。
【参考方案1】:
您的问题归结为为什么 ++
和 --
首先存在,而普通的 +
和 -
可以完成这项工作。
凭借今天的编译器优化功能,这完全是出于历史原因。 ++
和 --
可以追溯到 C 语言的早期(但不是最早)。The Development of the C Language 由 C 语言的作者 Dennis Ritchie 提供一些有趣的历史见解:
Thompson 更进一步,发明了
++
和--
运算符, 哪个递增或递减;[...]
它们不在B 的最早版本中,但是 一路上出现。
[...]
更强大的动力 因为创新可能是他观察到的翻译
++x
小于x=x+1
。
因此,确切的原因似乎在历史的迷雾中消失了,但 Ritchie 的这篇文章强烈建议递增和递减运算符的存在归因于早期编译器的性能问题。
当 C++ 被发明时,与 C 的兼容性是其发明者 Bjarne Stroustrup 的主要设计目标之一,因此不用说所有 C 运算符也存在于 C++ 中。正如 Stroustrup 本人在他的 FAQ 中所说:
我希望 C++ 兼容一门完整的语言 性能和灵活性,即使是最苛刻的系统 编程。
至于 C#,其发明者之一 Eric Lippert once stated here on the Stack Exchange network 表示 C# 支持它们的唯一原因是与旧语言的一致性:
[...] 这些运算符是可怕的功能。它们非常令人困惑;后 25 年多来,我仍然混淆了前后语义。他们 鼓励不良习惯,例如将结果评估与 副作用的产生。如果没有这些功能 C/C++/Java/javascript/etc,它们不会是为 C# 发明的。
P.S.:C++ 很特别,因为正如您所提到的(即使使用不正确的词“覆盖”),您可以重载所有这些运算符,这导致了++
和@987654338 @ 在许多程序员的脑海中呈现出略微不同的语义。它们有时读作“前进”(“后退”)或“向前迈出一步”(“向后迈出一步”),通常使用迭代器。如果您查看 C++ 中的 ForwardIterator 概念,您会发现它只需要一元 ++
。
【讨论】:
【参考方案2】:答案很简单。
一元运算意味着运算符将仅对操作数进行运算。
接下来的 i++ 和 i+=1 都是不同的动作。
-> 当 i++ 执行你时,编译器将进入变量位置并增加值。
-> i+=1 执行 i 并且 1 将加载到寄存器/临时变量中,并且将完成加法操作并将新值复制到 i 地址位置。
因此,与 i+=1 相比将是与 i++ 相比的成本。
【讨论】:
我希望编译器应该为++i
和i+=1
发出完全相同的机器代码。
如果硬件有一个特定的加一指令,在某些系统上称为INC
,那么编译器肯定会将它用于这两个操作。
这完全是编译器的设计,在高级编译器中会将 ++i 和 i+=1 转换为相同的机器码。但是这个操作背后的原始逻辑。
@Kancham:我不认为现在编译器必须特别先进。以上是关于为啥递增和递减是一元运算的主要内容,如果未能解决你的问题,请参考以下文章
重载运算与类型转换——基本概念,输入和输出运算符,算术和关系运算符,赋值运算符,下标运算符,递增和递减运算符,成员访问运算符