萍聚社区-德国热线-德国实用信息网

 找回密码
 注册

微信登录

微信扫一扫,快速登录

萍聚头条

楼主: musicbug

很奇怪的错误,我怎么都看不出来,高手指点一把,不胜感激!!!

[复制链接]
 楼主| 发表于 2003-2-15 18:27 | 显示全部楼层

你的问题,我已经请教了别人。希望你看后可以明白

发信人: thrust (小猪哼哼*减肥中), 信区: Programming
标 题: 总结修订版
发信站: The unknown SPACE (Fri Feb 14 15:13:58 2003), 转信

看看也差不多了, 牛鬼蛇神们也都出来了. 俺总结两句, 大家觉得不对可以指出来.
我手头没有C的标准, 是按照C++的来写的, 我想大概对C也好用. 如果不是, 请告
诉我.

C/C++语言的表达式计算顺序由好几个因素决定. 第一个, 最明显的, 如果A运算
的操作数是B运算的结果, 那么肯定B要比A先算. 比如a+b*c, 那肯定先做乘法.
第二个, 一个表达式中可能有一个到多个sequence point. 翻译一下, 就是说,
规定所有应该在point之前的运算,必须在所有point之后的运算之前完成. 至于
point之前的这些运算中哪个先做, 哪个后做, 是没有规定的. 其余的项目未作
规定, 如果产生二义性, 那说明你的表达式不合理. 这里我说的不合理, 意思是
标准未经定义的行为, 编译器可以根据自己的需要进行解释, 倒不一定会产生编
译错误.
比如说, 下面的表达式是不合理的:
a=(++i)*(i+1);
// 中间的乘法肯定要最后做. 但是左右两边先算哪个? 先算++i, 那么式子
// 变成(i+1)*(i+2), i++, 先算i+1, 那么式子变成(i+1)*(i+1), i++,
// 有二义性.
*++b=*b*2;
// 中间的赋值是最后做, 但是左右先算哪个? 不知道.

有一点要注意: 括号并不代表先被计算. 比如,
a=(++i)+i;
// 是一个不合理的式子. 并不是说, ++i外面有括号, 就会被先计算了;
// 事实上, C++标准根本就没有规定precedence, 完全是用语法来规定的.
// 而(++i)和i同为primary expression, 它们两个哪个先算是没规定的.

按照规定, sequence point 有这么几类:
第一, 表达式运算完成是一个sequence point.
第二, 函数调用之前, 所有的参数计算完毕, 是一个sequence point.
第三, 函数返回值被copy之后, 是一个sequence point.
第四, a&&b, a||b, a?b:c, a,b四种运算符: 在a算完之后是一个sequence point.

解释一下. 第一条没什么好说的. 第二条, 函数的参数计算完后才开始执行函数.
第三条, 函数的返回值copy完以后, 才开始算其它的部分. 把二和三合起来看,
一个函数的执行和其返回值的copy是一个整体, 中间不插入对表达式其它部分的
计算. 这里的函数是广义的, 包括操作符重载, inline function, 隐式的类型转
换函数等等. 第四条, 说明第一个操作数总是比其它的要先计算.

另一条很重要的规定: 在两个sequence point之间, 一个标量最多只能被修改一次.
如果修改一次以上, 则其结果未定义. 因此如下的表达式都是不合理的:
a=(++i)+(++i);
// 这个表达式只有最后一个sequence point, 因此修改两次i是不合理的.
i+=++i;
// 同上面一样. ++i和i+=...修改了两次i.
而以下的表达式是合理的:
a=(++i)==(++j);
// i和j各被修改了一次.
a=(++i) && (++i);
// 这个式子中间有一个sequence point: 在算完第一个++i之后. 因此, 这个
// 表达式被分成了两段, 每段修改了一次i, 是允许的.
a=(++i==++j) && (++i==++j);
// 同上.

牵涉到函数调用是一样的道理. 比如说:
cout<<++a<<++a;
// 其实是翻译成:
operator<< (operator<< (cout,++a),++a);
// 这是个不合理的式子. 函数调用的参数计算顺序是未作规定的; 外层函数调用,
// 可以先计算第一个参数, 又是一个函数调用, 使a+1并遇上两个sequence point;
// 再算第二个参数, a++并再遇上两个sequence point, 这里没有问题.
// 但是如果先计算第二个参数, 那么a++, 然后计算第一个参数, 发现函数调用,
// 分别计算里层的参数, a又加一, 其值改变了两次, 这结果就是未定义的.

修订:
我见过很多教科书上说前缀++和后缀++的区别: 前缀++在整个表达式计算前
先加, 后缀++在整个表达式计算后再加. 其实这是片面的. 前后缀的区别仅仅在于,
(++i)的结果是i+1,而(i++)的结果是i. (当然最后i都被加了1, 但那只是side effect.)
并不存在前缀是在整个表达式之前计算, 后缀是在表达式之后计算的说法, 编
译器可以在满足sequence point 限制的条件下, 自由地选择+1的时间.
自减运算--也是类似的.
另一个区别是, 前缀++/--的结果是个lvalue, 而后缀的结果是rvalue.
事实上, ++i和i+=1是等价的.

--
(我还是忘不了猪的事)

※ 修改:.thrust 于 Feb 14 15:15:42 修改本文.[FROM: 128.205.]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
发表于 2003-2-16 17:37 | 显示全部楼层
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
发表于 2003-5-15 15:42 | 显示全部楼层
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
发表于 2003-9-7 11:04 | 显示全部楼层
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
您需要登录后才可以回帖 登录 | 注册 微信登录

本版积分规则

手机版|Archiver|AGB|Impressum|Datenschutzerklärung|萍聚社区-德国热线-德国实用信息网 |网站地图

GMT+2, 2024-6-15 03:32 , Processed in 0.054599 second(s), 14 queries , MemCached On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表