| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 594 人关注过本帖
标题:(求助)关于自增量的问题!!!
只看楼主 加入收藏
senbiancheng
Rank: 1
等 级:新手上路
帖 子:14
专家分:0
注 册:2009-4-14
结帖率:66.67%
收藏
已结贴  问题点数:10 回复次数:12 
(求助)关于自增量的问题!!!
程序代码:
#include <iostream>
using namespace std;
int main()
{
int i=5,k;
k=(++i)+(++i);
cout<<k<<endl;
return 0;
}
结果为何为14,求运算过程,折磨我一天了。
2013-02-01 18:43
fanpengpeng
Rank: 8Rank: 8
来 自:南极洲
等 级:蝙蝠侠
威 望:7
帖 子:299
专家分:849
注 册:2013-2-1
收藏
得分:5 
你好,我也刚学C++,这个问题之前在网上看到有高手解答过
关于前置自增和后置自增的区别,书上通常只是简单的说“先加再算”和“先算再加”
但是这个规则在具体编译器实现的时候,被处理成“表达式计算前加”和“表达式计算后加”
这里的表达式指的是“(++i)+(++i)”这个大表达式,所以14的结果可以这样解释:
1.表达式计算前先进行自增操作 ++i 两次后 i = 7
2.7+7 = 14
而不是我们所想的:6+7 = 13
关于这个问题有下面两个表达式可以计算一下
(i++)+(i++)  //5+5 = 10 i = 7
(++i)+(i++)  //6+6 = 12 i = 7
当然这个解释只做参考啊,不过我认为,编程时还是要尽量少写一些语言标准未定义其行为的语句。

人生是一场错过 愿你别蹉跎
2013-02-01 20:41
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9008
专家分:53957
注 册:2011-1-18
收藏
得分:5 
这属于未定义行为,出什么结果都有可能
如果你想深入了解,请Google“序列点和副作用”
2013-02-02 08:18
senbiancheng
Rank: 1
等 级:新手上路
帖 子:14
专家分:0
注 册:2009-4-14
收藏
得分:0 
多谢 我先理解下
2013-02-02 19:18
senbiancheng
Rank: 1
等 级:新手上路
帖 子:14
专家分:0
注 册:2009-4-14
收藏
得分:0 
如果如2楼所说,那么下面这个代码
程序代码:
#include <iostream>
using namespace std;
int main()
{
    int j=5,k;
    k=(j)+(++j)+(j)+(++j)+(j);
    cout<<"k:"<<k<<endl;
    return 0;
}
我的计算过程:
因为前置自增是先加再算,那么经过两次自增J就变为了7了
那么  k=7+7+7+7+7
那么K=35,我调试出来是32,为何?编译器问题吗,求各位大神帮助。
2013-02-02 19:31
fanpengpeng
Rank: 8Rank: 8
来 自:南极洲
等 级:蝙蝠侠
威 望:7
帖 子:299
专家分:849
注 册:2013-2-1
收藏
得分:0 
呵呵,很棒,学习语言就是要有跟细节问题叫板的决心,不做半调子程序员。
我以前的C语言老师就跟我们说过C语言的细节问题是永远都无法全部弄清的,可见细节问题确实不好对付,要坚持。
好了,不说废话了,下面谈一些关于这个自增问题我个人的一点看法,仅供参考。
首先:k=(j)+(++j)+(j)+(++j)+(j);k值为32,我的解释是 6+6+6+7+7 = 32.
这是为什么呢?不着急,我们从头开始慢慢谈。
第一个概念:序列点和副作用
首先感谢3楼,我是看到3楼的回帖才听说这个概念的,这两个概念谈的都是C语言的表达式计算。
所谓副作用,这里粗糙的说就是表达式中变量的值被修改。
为什么叫副作用呢,因为表达式的主要作用是返回求解的值,你可能听说过每个表达式都会返回一个值之类的话,说的就是这个意思。
相对于表达式返回值这一主要作用,由于表达式的求解而对变量值产生的修改被称之为副作用。
所谓序列点,这里也粗糙的说,就是表达式求解过程中的一些时刻点,比如说2+5*3这个式子,先乘后加,那么这里先和后的两个动作之间,我们就说有一个序列点
关于序列点和副作用之间的关系,有这样一句话需要仔细理解:
在序列点上,该点之前所有运算的副作用都应该结束,并且后继运算的副作用还没发生。
这里我们就简单的这样理解,如果表达式中有序列点,也就是有明确的先算和后算之分,那么先的那部分算完后变量就会被修改,然后再接着算后面的。
那么表达式中哪些地方会产生序列点呢,我觉得有明确求值顺序的地方就有序列点。
第二个概念:表达式求值顺序
先介绍一下C语言中的表达式:
1.由操作符和操作数构成表达式
2.表达式可以嵌套
哪些因素会影响到求值顺序呢。有三点:操作符自身规定的求值顺序,优先级,结合性
被规定有明确求值顺序的操作符有三个 (&& ||)、(?:)、(,)这三类操作符都规定先算左操作数。除此之外,其他操作符都没有定义求值顺序,这也是产生未定义的原因
由于表达式可以嵌套,a+b+c 是两个简单表达式嵌套而成的复杂表达式,子表达式的求值顺序由操作符的优先级决定,相同优先级的由结合性确定
如a+b*c *优先级比+高 则先求解b*c 再求解a+(),再如a+b+c 由于优先级相同,+具有左结合性,则先算a+b 再算()+c
有一点值得提出:尽管不是所有操作符都定义了自身的求值顺序,但所有操作符几乎都有明确的优先级和结合性,
因此多个操作符的复杂表达式的各个子表达式的求值顺序几乎总是确定的。
嗯,说了这么多,现在可以来看看上面这个表达式了
(j)+(++j)+(j)+(++j)+(j)
首先:+号的左结合性,j+(++j)这里产生一个序列点,++比+有更高的优先级产生一个序列点,那么在算+之前j的值应该被修改为6,++j自身也是返回6的 所以6+6=12
这样在第一个+号产生的序列点上,表达式变为 12+j+(++j)+j
接着:12+j 注意此时j已经是被明确修改为6了 所以 12+6 = 18 表达式变为18+(++j)+j
继续:18+(++j) 应该是 18+7 = 25 没错吧
最后:25 + j 同样的 由于上一个序列点的存在,这里的j已经明确为7了 所以 25+7 = 32
解释完了。
补充说明(关于(j++)+(j++)的重新解释):
再看一下++j 和 j++,一开始说 这个是先算后加 先加后算,又有先后了,这里也有序列点在里面?
注意:这个先后跟序列点无关。++j返回的是变量j之身的引用,j++返回的是一个临时变量的常引用,可以说++j还是j,但j++已经跟j关系不大了
这里先算后算的只是说他们的表达式返回的值的差别而不是说求值顺序,需要澄清。
(j++)+(j++),5+5=10,怎么解释。根据上面分析,先算两个j++ 再算+
注意:两个j++没有定义顺序,也就是没有序列点,j++后j的值在什么时候修改,
根据序列点的定义只要在进行+运算前修改就行了,可以在第一个j++后就修改,也可以等两个j++都算完后。看来编译器是放在+号之前
j++ 返回5 j还是5 再j++ 返回5 要算+了 产生副作用 j变成7
(j++)+(++j)也要重新解释:j++ 返回5 ++j 返回j自身,在算+号前 j产生副作用变为7 所以 +求解 为 5+7 = 12
(++j)+(++j)一样 算完++j后,在算+之前j = 7,而++j返回j自身,所以j+j=14
这是关于上面回帖的重新解释 那个有点粗糙,不好意思。
但是这里还有一个问题:我无法解释j+(j++)为什么会返回10,按我的理解,我觉得应该是j++返回5,j为6 应该是11

人生是一场错过 愿你别蹉跎
2013-02-03 16:19
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9008
专家分:53957
注 册:2011-1-18
收藏
得分:0 
回复 6楼 fanpengpeng
你贴的这段文字是从哪儿弄来的?
我Google了一下,随机挑两个搜索出的链接给你看看
http://kimva.
http://www.
2013-02-04 09:12
fanpengpeng
Rank: 8Rank: 8
来 自:南极洲
等 级:蝙蝠侠
威 望:7
帖 子:299
专家分:849
注 册:2013-2-1
收藏
得分:0 
这个我也弄不清楚了
刚才用VC反汇编了代码看了, k=(j)+(++j)+(j)+(++j)+(j);
确实被处理成:
j=j+1;
j=j+1;
k=j+j+j+j+j; //k=35
上面的代码不是贴的 是我自己写的 我试图解释k=32的原因,c-free调出来也是32
但是无法反汇编
关于序列点,;号和那三个操作符肯定是产生序列点的 但是由于优先级和结合性产生的先后运算顺序该不该处理成序列点,我认为应该是处理的
但VC显然没有这么做
这个还是看反汇编吧 c-free的生成文件无法反汇编 否则我可以看看他具体怎么弄了

人生是一场错过 愿你别蹉跎
2013-02-04 09:49
fanpengpeng
Rank: 8Rank: 8
来 自:南极洲
等 级:蝙蝠侠
威 望:7
帖 子:299
专家分:849
注 册:2013-2-1
收藏
得分:0 
网上搜索了 优先级 结合性与序列点
原来我上面犯了一个容易犯的错误,优先级和结合性并不规定求值顺序
帖子地址:
http://bbs.
原先我一直认为优先级高的会先算,其实不是这样的 他唯一作用是决定哪些操作数是属于哪些操作符
如果这样的话 那k=32 我实在无法解释了 如果实在想弄清楚 还是想办法反汇编吧
不过这样看来的话 去研究为什么会产生这些结果 确实没有意义了
我觉得这个问题到现在我有两点体会:
1. 不写这样的代码
2. 深刻理解序列点,这是标准定义的概念,以前没有接触过,现在学习了
关于序列点,我搜索了两个关键词,
1. 序列点和副作用
2. 优先级 结合性与序列点
第二个关键词纠正了我上面的错误认识

人生是一场错过 愿你别蹉跎
2013-02-04 10:21
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9008
专家分:53957
注 册:2011-1-18
收藏
得分:0 
回复 8楼 fanpengpeng
在这个表达式内部,没有序列点
通过反汇编来反推C标准,在任何情况下皆无任何用处
2013-02-04 10:25
快速回复:(求助)关于自增量的问题!!!
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017704 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved