关于for(),为什么使用i ++而不是++ i?

也许它在优化后对编译器无关紧要,但在C / C ++中,我看到大多数人以下列forms制作for循环:

for (i = 0; i < arr.length; i++) 

使用post fix ++完成递增的地方。 我得到了两种forms之间的区别。 i ++返回i的当前值,但是在静音时将i加1。 ++我首先向i添加1,并返回新值(比我多1)。

我认为i ++需要更多的工作,因为除了下一个值之外还需要存储先前的值:Push *(&i)to stack(或load to register); 增量*(&i)。 Versus ++ i:增量*(&i); 然后根据需要使用*(&i)。

(我得知“递增*(&i)”操作可能涉及寄存器加载,具体取决于CPU设计。在这种情况下,i ++需要另一个寄存器或堆栈推送。)

无论如何,在什么时候,为什么,我变得更时尚?


我倾向于相信azheglov:这是一个教育学的东西,因为我们大多数人在Window或* nix系统上做C / C ++,编译器质量很高,没有人受伤。

如果您使用的是低质量编译器或解释环境,则可能需要对此敏感。 当然,如果你正在进行高级C ++或设备驱动程序或嵌入式工作,希望你已经足够经验丰富,这根本不是什么大问题。 (狗有佛性吗?谁真的需要知道?)

我的理论(为什么i ++更流行)是当人们学习C(或C ++)时,他们最终会学习如下代码迭代:

 while( *p++ ) { ... } 

请注意,修复后的表单在这里很重要(使用中缀表单会创建一次性类型的错误)。

当编写一个for循环,其中++ii++并不重要时,使用后缀forms可能会更自然。

补充:我上面写的内容真的适用于原始类型。 在使用原始类型编写代码时,您倾向于快速地执行操作并自然地执行操作。 这是我需要依附于我的理论的重要警告。

如果++是C ++类上的重载运算符(Rich K.在评论中建议的那种可能性),那么当然你需要非常小心地编写涉及这些类的循环,而不是自然地做简单的事情。

你使用哪个并不重要。 在一些极其过时的机器上,在某些情况下使用C ++, ++i更有效,但现代编译器如果没有存储则不存储结果。 至于什么时候它变得流行到for循环中的postincriment,我的K&R第二版副本使用第65页上的i++ (我翻阅时发现的第一个循环。)

出于某种原因, i++在C i++变得更加惯用 ,即使它创造了一个不必要的副本 。 (我认为这是通过K&R,但我认为这在其他答案中存在争议。)但我不认为C中存在性能差异,它只用于内置函数,编译器可以优化复制操作

然而,它确实在C ++中有所作为,其中i可能是一个用户定义的类型,其中operator++()被重载。 编译器可能无法断言复制操作没有可见的副作用,因此可能无法消除它。

至于原因,这里是K&R在这个问题上所说的话:

Brian Kernighan

你必须问丹尼斯(它可能在HOPL论文中 )。 我有一个暗淡的记忆,它与pdp-11中的后增量操作有关,虽然超出我不知道的范围,所以不要引用我。

在c ++中,迭代器的首选样式实际上是++ i,用于一些微妙的实现原因。

丹尼斯里奇

没有特别的原因,它只是变得时髦。 生成的代码在PDP-11上是相同的,只是一个inc指令,没有自动增量。

HOPL纸

汤普森更进一步发明了++和 – 运算符,它们递增或递减; 它们的前缀或后缀位置确定更改是在注意操作数的值之前还是之后发生。 它们不是最早版本的B,而是出现在路上。 人们经常猜测它们的创建是为了使用DEC PDP-11提供的自动递增和自动递减地址模式,C和Unix首先在这些模式中流行起来。 这在历史上是不可能的,因为在开发B时没有PDP-11。 然而,PDP-7确实有一些“自动增量”存储单元,其特性是通过它们的间接存储器引用增加了单元。 这个function可能会向Thompson建议这样的操作员; 使它们成为前缀和后缀的概括是他自己的。 实际上,自动增量单元并没有直接用于运算符的实现,并且创新的更强烈动机可能是他观察到++ x的翻译小于x = x + 1的翻译。

对于整数类型,当您不使用表达式的值时,两个表单应该是等效的。 在具有更复杂类型的C ++世界中,这已不再适用,但在语言名称中保留。

我怀疑“i ++”在早期变得更受欢迎,因为这是原始K&R“The C Programming Language”一书中使用的风格。 你必须问他们为什么选择这种变体。

因为一旦你开始使用“++ i”,人们就会感到困惑和好奇。 他们将停止日常工作并开始谷歌搜索解释。 12分钟后,他们将进入堆栈溢出并创建一个这样的问题。 瞧,你的雇主又花了10美元

比K&R更进一步,我看了它的前身: Kernighan的C教程 (〜1975年)。 这里的前几个例子使用++n 。 但是每个for循环使用i++ 。 所以回答你的问题:几乎从一开始i++就变得更时尚了。

在某种程度上它是惯用的C代码。 这就是通常的事情。 如果那是你的巨大性能瓶颈,你可能会遇到一个独特的问题。

然而,看看我的K&R The C Programming Language ,第1版,我在循环中找到的第一个实例(第38页)确实使用++ i而不是i ++。

我认为随着C ++的创建,它变得更加时髦,因为C ++使你能够在非平凡的对象上调用++。

好吧,我详细说明:如果你调用i++并且i是一个非平凡的对象,那么在增量之前存储包含i值的副本将比指针或整数更昂贵。

我认为我的前任对于选择增加后增量的副作用是正确的。

因为它的时尚性,它可能就像你在for语句中以相同的重复方式开始所有三个表达式一样简单,这是人类大脑似乎倾向于的东西。

我会加上其他人告诉你的主要规则是:保持一致。 选择一个,除非是特定情况,否则不要使用另一个。

如果循环太长,则需要重新加载缓存中的值以在跳转到开始之前递增它。 你不需要++ i,没有缓存移动。

在C中,除了前缀inc / dec之外,导致变量具有新值的所有运算符都修改左手变量 (i = 2,i + = 5等)。 因此,在++ i和i ++可以互换的情况下,许多人对i ++更加满意,因为操作员在右侧,修改左手变量

如果第一句话不正确,请告诉我,我不是C的专家。