ret*_*dev 2 c pre-increment post-increment
我正在通过K&R工作,现在正在练习1-16.我发现到目前为止,书中只使用了预增量.
大多数其他教程书籍和我见过的源代码往往倾向于后增量,除非有明显的影响,例如while循环等.
这是K&R的风格或技术考虑吗?或者我只是需要进一步完成这本书以获得我的答案?!
大约1000万年前,在优化编译器之前,这曾经很重要*.它真的不再了.理由store是需要额外的操作才能以天真的方式实现后增量.虽然编译器大多数都没有以这种方式实现它,所以在给定上下文并信任编译器做正确的事情时,更喜欢哪种样式更有意义.
*JimBalter正确地指出这不是一个问题,我不应该暗示它曾经可能有重要意义.
这有几个方面.
语义
预增量(递减)和后递增(递减)的语义是不同的.前者在使用该值之前递增一个值,而后者在使用后递增一个值.例如
unsigned i;
for (i=0; i<10; i++ /* ++i */ ) { }
Run Code Online (Sandbox Code Playgroud)
在这种情况下,无论是使用前增量还是后增量都无关紧要.这让我想到了第二个方面:
上下文
有时使用前增量或后增量确实很重要,这取决于使用的上下文.请考虑以下示例:
char *p = "some string";
unsigned len = 0;
// test 1
while ('\0' != *p++) { len++; }
// test 2 (assumes that p points to a non-empty string)
while ('\0' != *++p) { ++len; }
Run Code Online (Sandbox Code Playgroud)
结果test 1是字符串的长度,结果test 2是字符串的长度减去1.因为增加的值p被用作表达式的一部分,它确实物质当增量发生的情况:使用后p在表达式(测试1),或之前它的使用(试验2).因为len不使用作为表达式的一部分,它并不重要一个是否使用前或后增量.
这让我想到了第三个方面.
履行
为了实现后增量,p必须将其存储起来以供以后使用以增加它,这会为临时值占用额外的存储空间.预增量不需要临时存储空间.但是,如果递增的值不用作表达式的一部分,那么现代优化编译器能够为前后增量生成相同的代码,其中需要临时值来评估该表达式.
这让我想到了第四个方面(在上一段中略有暗示),但这与C++有关.
性能
在C++中,递减和递增运算符可以被重载(链接)以使用复杂类型,并且STL(链接)确实充分利用它来为其容器类型实现迭代器(链接).在那种情况下,一个值就像
set::iterator it;
Run Code Online (Sandbox Code Playgroud)
可能是一个相当复杂的事情,而不仅仅是一个简单的状态(即它不仅仅是一个原始整数).在这种情况下,使用预增量++it 确实会对后增量产生影响,it++因为如果在表达式中使用(例如上下文),则不需要像临时增量那样存储临时值.这可以节省一些运行时开销.