Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C K&;R似乎更喜欢预增量_C_Post Increment_Pre Increment - Fatal编程技术网

C K&;R似乎更喜欢预增量

C K&;R似乎更喜欢预增量,c,post-increment,pre-increment,C,Post Increment,Pre Increment,我通过K&R工作,目前正在练习1-16。我突然想到,到目前为止,书中只使用了预增量 大多数其他教程和我见过的源代码都倾向于后期增量,除非有明显的影响,比如在while循环中 这是K&R在风格上还是技术上的考虑?还是我只需要进一步阅读这本书就能得到我的答案 大约1000万年前,在优化编译器出现之前,这曾经很重要*。现在真的没有了。其基本原理是,需要额外的存储操作,以便以简单的方式实现增量后。不过,编译器通常不会以这种方式实现它,所以只要根据上下文选择更合理的样式,并相信编译器会做正确的事情 *Ji

我通过K&R工作,目前正在练习1-16。我突然想到,到目前为止,书中只使用了预增量

大多数其他教程和我见过的源代码都倾向于后期增量,除非有明显的影响,比如在while循环中


这是K&R在风格上还是技术上的考虑?还是我只需要进一步阅读这本书就能得到我的答案

大约1000万年前,在优化编译器出现之前,这曾经很重要*。现在真的没有了。其基本原理是,需要额外的
存储
操作,以便以简单的方式实现增量后。不过,编译器通常不会以这种方式实现它,所以只要根据上下文选择更合理的样式,并相信编译器会做正确的事情

*JimBalter正确地指出,这从来都不是问题,我也不应该认为这曾经很重要。

我会说(即使由于后缀运算符的优先级较高,标准中的后增量运算符排在第一位)预增量是增加对象值的自然方式,因此如果您只想增加对象值,那么使用预增量是一个很好的理由


(++E)
相当于
(E++=1)
,但不是
(E++)

语义

增量前(减量)和增量后(减量)的语义是不同的。前者在使用值之前增加值,后者在使用值之后增加值。比如说

unsigned i;
for (i=0; i<10; i++ /* ++i */ ) { } 
test1
的结果是字符串的长度,
test2
的结果是字符串的长度减去1。由于增量值
p
用作表达式的一部分,因此增量发生的时间很重要:在表达式中使用
p
之后(测试1),或者在使用之前(测试2)。因为
len
不作为表达式的一部分使用,所以使用前增量还是后增量都无关紧要

这就引出了第三个方面

实施

为了实现后期增量,必须存储
p
的值,以便以后用于增量,这会为临时值占用额外的存储空间。预增量不需要临时存储空间。但是,现代优化编译器能够为增量前和增量后生成相同的代码,前提是增量值不作为表达式的一部分使用,而表达式需要临时值来计算该表达式

这使我进入了第四个方面(前一段有点暗示),但这与C++相关。 性能

在C++中,递减和增量运算符可以重载()以配合复杂类型,并且STL()确实大量使用它来实现迭代器()用于其容器类型。在这种情况下,值

set::iterator it;

它可以是一个相当复杂的东西,状态不只是简单的(也就是说,它不仅仅是一个原始整数)。在这种情况下,使用增量前的
++it
确实比增量后的
it++
有所不同,因为不需要像在表达式中使用增量后所需的那样存储临时值(请参见上下文)。这可以节省相当多的运行时开销。

它可能也与PDP-11指令集有关。虽然不是完全相同,但非常相关:PDP-11具有后增量和前减量。方便进行堆栈操作。@PaulR“它可能也与PDP-11指令集有关。”——丹尼·里奇明确地说它不是。。。这些操作在C和它的前辈早于PDP-11@ C.LAN“技术上的预入/减量需要较少的步骤”这是简单的错误。这仍然与C++和迭代器有关,其中代码> >操作符++/>代码>和<代码>运算符-<代码>被重载,操作更加复杂。但是,对于像
int
这样的简单类型,这并不重要。在高质量优化编译器之前,我选择了一个保守的下限。对于任何编译器?我记得几年前为班级编写了一个非常糟糕的C编译器,几乎肯定会受到这个问题的困扰。@C.Lang:正确。“额外步骤”是存储一个临时值。这里有一些关于“C++和增量前/后”的有趣讨论。但是最好自己编写一个测试并查看反汇编:)但是值得指出的是@JimBalter实际上是正确的。我错误地指出,它可能是特定情况(即循环条件)之外的问题,在这种情况下,它可能是一个问题。谢谢你,金巴特!回答得很好,谢谢。另外,为什么要将
null
*p++
进行比较,而不是相反?也就是说,
while('\0'!=*p++)
not
while(*p++!='\0')
。后者对我来说更直接。@retrodev:我的习惯是避免意外的任务。如果我写
If(x==5)
那么像
If(x=5)
这样的打字错误会导致一个始终为真的赋值。然而,如果我写
if(5==x)
,那么同样的输入将产生一个编译器错误,因为我不能将值
x
分配给积分
5
。关于实现的部分(有些)错误。如果需要temp,那么优化器无法消除它。是否需要它并不取决于它是否是基元类型,而是在增量发生后是否必须访问预增量值。。。对于基元类型也是如此。实际上,迭代器总是如此,因为迭代器具有全局状态,并且必须在迭代器中更新该全局状态
set::iterator it;