(注意:我不是在询问预增量与后增量的定义,或者它们在C / C ++中的使用方式。因此,我不认为这是一个重复的问题。)
C的开发人员(Dennis Ritchie等人)出于很好的理由创建了递增和递减运算符。我不明白为什么他们决定创造前后增量/减量的区别?
我的感觉是,当C开发时,这些运算符比今天更有用。大多数C / C ++程序员使用其中一种,而来自其他语言的程序员今天发现这种区别奇怪且令人困惑(注意:这完全基于轶事证据)。
为什么他们决定这样做,以及计算上发生了什么变化,这种区别今天没那么有用?
对于记录,两者之间的差异可以在C ++代码中看到:
int x = 3;
cout << "x = 3; x++ == " << x++ << endl;
cout << "++x == " << ++x << endl;
cout << "x-- == " << x-- << endl;
cout << "--x == " << --x << endl;
将作为输出
x++ == 3
++x == 5
x-- == 5
--x == 3
答案 0 :(得分:10)
当时硬件广泛支持递增和递减1:单个操作码和快速。这是因为&#34;递增1&#34;并且&#34;递减1&#34;在代码中是一个非常常见的操作(直到今天)。
post-andcrecrement表单只影响在生成的机器代码中插入此操作码的位置。从概念上讲,这模仿&#34;在使用结果&#34;之前或 之前增加/减少。在一个声明中
i++;
&#39>之前/之后&#39;概念未被使用(因此它与++i;
相同),但在中
printf ("%d", ++i);
是的。现在这种区别与设计语言C时的区别同样重要(这个特殊的习语是从它的前身“#34; B&#34;”中复制而来。)
来自The Development of the C Language
此功能[PDP-7&#34;`自动增量&#39;记忆细胞&#34;]可能会向Thompson [Ken Thompson,他设计&#34; B&#34;,C的前身]建议这样的操作员;使它们成为前缀和后缀的概括是他自己的。实际上,自动增量单元并没有直接用于运算符的实现,而且创新的更强烈动机可能是他观察到++ x的翻译小于x = x + 1的翻译。
感谢@dyp提及此文档。
答案 1 :(得分:5)
当你从n
倒数时,无论是预减还是减后都是非常重要的
#include <stdio.h>
void foopre(int n) {
printf("pre");
while (--n) printf(" %d", n);
puts("");
}
void foopost(int n) {
printf("post");
while (n--) printf(" %d", n);
puts("");
}
int main(void) {
foopre(5);
foopost(5);
return 0;
}
答案 2 :(得分:2)
为了得到超出猜测的答案,很可能你必须亲自询问Dennis Ritchie等人。
添加已经给出的答案,我想补充两个可能的原因:
懒惰/节约空间:
您可以使用while(--i)
与while(i--)
等结构中的相应版本在输入文件中保存几个击键/字节。 (看看pmg的答案,看看为什么两者都有所不同,如果你在第一次运行中没有看到它的话)
美学
出于对称的原因,只有一个版本的前后增量/减量可能会让人觉得缺少某些东西。
编辑:在推测部分的输入文件中添加了少量字节,现在提供了一个非常好的&#34;历史性的&#34;原因也是。
无论如何,整理清单的主要目的是提供一些可能的解释,这些解释不是太历史性,但仍然在今天举行。
当然我不确定,但我认为要求一个历史性的&#34;个人品味之外的其他原因是从一种不必要的假设出发。
答案 3 :(得分:2)
对于C
让我们来看看Kernighan&amp; Ritchie原始辩护(原始K&amp; R第42和43页):
不寻常的方面是++和 - 可以用作前缀或 作为后缀。 (...)在没有值的情况下(..)选择 根据品味的前缀或后缀。但是htere就是这样的情况 一个或另一个是专门要求的。
本文继续介绍一些在索引中使用增量的示例,明确的目标是编写&#34; 更紧凑 &#34;码。因此,这些运算符背后的原因是更紧凑的代码的便利性。
给出的三个示例(squeeze()
,getline()
和strcat()
)仅使用索引在表达式中使用后缀。作者将代码与不使用嵌入式增量的较长版本进行比较。这证实了重点是紧凑性。
K&amp; R高亮显示第102页,将这些运算符与指针解除引用结合使用(例如*--p
和*p--
)。没有给出进一步的例子,但同样,他们明确表示这种好处是紧凑的。
对于C ++
Bjarne Stroustrup希望具有C兼容性,因此C ++继承了前缀和后缀增量和减量。
但还有更多内容:在他的书中&#34; C ++的设计与发展&#34;,Stroustrup解释说,最初,他计划只有一个重载用户定义的类中的后缀和前缀:
有几个人,特别是Brian Kernighan,指出了这一点 从C角度看,限制是不自然的,并且阻止了用户 定义一个可以用作替代的类 普通的指针。
这导致他找到当前的签名差异来区分前缀和后缀。
顺便说一下,没有这些操作符,C ++就不会是C ++而是C_plus_1; - )
答案 4 :(得分:1)
考虑以下循环:
select er_mental,
case when ISNUMERIC(er_mental) = 1 then
case when er_mental > 1 then 'Yes'
when er_mental < 1 then 'No'
end
when er_mental = 'Not obtainable' then 'No'
end as er_mental_resp
from #hlq;
您无法通过预递减操作复制此循环,而无需在for(...)构造之外移动递减操作,并且最好进行初始化,交互和检查所有在一个地方。
一个更大的问题是:可以为一个类重载增量运算符(全部4)。但是后来运算符严重不同:后期运算符通常会导致正在创建的类实例的临时副本,而前运算符则不会。这在语义上是一个巨大的差异。
答案 5 :(得分:0)
PDP-11只有一条指令对应*--p
,另一条指令对应from collections import Counter
frequency_per_character = Counter(open(filename).read().lower())
(或可能反过来)。