搜索
bottom↓
回复: 22

求教两个简单的C语言问题

[复制链接]

出0入0汤圆

发表于 2013-4-25 00:59:38 | 显示全部楼层 |阅读模式
int main(void)
{
        int i=1;
        printf("%d,%d,%d",i,++i,i);
        return 0;
}
为什么结果是2,2,1?

int main(void)
{
        int i=1,j=2;
        printf("%d,%d,%d,%d",i,i++,i+=j,++j);
        return 0;
}
为什么结果是4,4,4,3?

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2013-4-25 02:30:32 | 显示全部楼层
百度到一些资料。不是是否合用
一是:printf函数中的计算是从右向左进行的。
二是:我们在写代码时,应该尽量避免类似下面的无确定意义的表达式出现,因为很有可能不同的编译器,会采用不同的理解方式。

出105入79汤圆

发表于 2013-4-25 02:58:52 来自手机 | 显示全部楼层
从右到左执行。很简单的。

出70入0汤圆

发表于 2013-4-25 10:07:12 | 显示全部楼层
很多人看代码都讨厌这种i+++++,逻辑不清晰,不要用分析这类问题来显酷。搜一下C语言序列点,副作用。

出0入0汤圆

发表于 2013-4-25 10:25:24 | 显示全部楼层
是右到左没错,但是想不明白为什么第二个函数的第一个i是4而不是5

出0入0汤圆

发表于 2013-4-25 12:19:56 | 显示全部楼层
是右到左,第二个理解应该编译优先权不一样

出0入0汤圆

发表于 2013-4-25 12:27:22 | 显示全部楼层
从右到左的话第二个不应该是5443吗?

出10入0汤圆

发表于 2013-4-25 13:12:12 来自手机 | 显示全部楼层
undefined behaviour

出0入0汤圆

发表于 2013-4-25 14:08:59 | 显示全部楼层
楼上正解.
入栈顺序是从右往左, 但是自增和加法操作不保证方向......和编译器有关.
可以看反汇编结果.
这种写法是考试坑爹的.

出0入0汤圆

发表于 2013-4-25 14:32:20 | 显示全部楼层
转一个:
C语言中,只包含一个表达式的语句,如x=(i++)*2;称为“表达式语句”。表达式语句结尾的";"是C标准定义的顺序点之一,但这不等同于说所有的";"都是顺序点,也不是说顺序点只有这一种。下面就是标准中定义的顺序点:
函数调用时,实参表内全部参数求值结束,函数的第一条指令执行之前(注意参数分隔符“,”不是顺序点);
&&操作符的左操作数结尾处;||操作符的左操作数结尾处;?:操作符的第一个操作数的结尾处;逗号运算符;
表达式求值的结束点,具体包括下列几类:
自动对象的初值计算结束处;表达式语句末尾的分号处;do/while/if/switch/for语句的控制条件的右括号处;for语句控制条件中的两个分号处;return语句返回值计算结束(末尾的分号)处。

定义顺序点是为了尽量消除编译器解释表达式时的歧义,如果顺序点还是不能解决某些歧义,那么标准允许编译器的实现自由选择解释方式。理解顺序点还是要从定义它的目的来下手。
再举一个例子:
y=(x++,x+1);
已知这个语句执行前x=2,问y的值是多少?
逗号运算符是顺序点。那么该表达式的值就是确定的,是4,因为按照顺序点的定义,在对x+1求值前,顺序点","前的表达式——x++求值的全部副作用都已发生完毕,计算x+1时x=3。这个例子中顺序点成功地消除了歧义。
注意这个歧义是怎样消除的。因为中间的顺序点使“相邻顺序点间对象的值只更改一次”的条件得到满足。
y=(x++)*(x++),执行前x=2,y=?
答案是,因为这个表达式本身不包含顺序点,顺序点未能消除歧义,编译器生成的代码使y取4,6(以及更多的一些可能值)都是符合标准定义的,程序员自己应为这个不符合顺序点定义的表达式造成的后果负责。

出0入0汤圆

发表于 2013-4-25 15:53:39 | 显示全部楼层
要避免这种用发 ,因为和编译器还有优化等级都有关系, 而且出了问题还很难查

出0入0汤圆

发表于 2013-4-25 19:47:25 | 显示全部楼层
第二个运行结果是5,4,4,3哦

出0入0汤圆

 楼主| 发表于 2013-4-26 00:44:30 | 显示全部楼层
wangshumou 发表于 2013-4-25 19:47
第二个运行结果是5,4,4,3哦

如果按照printf从右到左的顺序的话,我想也是5,4,4,3,但我用VC6.0是4,4,4,3

出0入0汤圆

 楼主| 发表于 2013-4-26 00:46:43 | 显示全部楼层
zhugean 发表于 2013-4-25 12:27
从右到左的话第二个不应该是5443吗?

但用VC6.0测确实是4,4,4,3

出0入0汤圆

发表于 2013-4-26 07:10:50 | 显示全部楼层
吃饱了没事情干吗???

出0入0汤圆

发表于 2013-4-26 08:59:17 | 显示全部楼层
小德GD 发表于 2013-4-26 00:46
但用VC6.0测确实是4,4,4,3
printf("%d,%d,%d,%d",i,i++,i+=j,++j);

唉......VC 的结果既然是这样, 我就给解释下吧.
首先从右往左:
++j 后 j 变成了 3, 注意前加操作是先自增后赋值.
i += j 后 i 变成了 1 + 3 = 4;
i++ 时, 由于后加操作是先赋值后自增, 所以, i 还是 4.
i, 当然也是 4, 因为 , 号不是序列点.

如果你用 GCC 的话, 结果会不一样, 他的前加后加操作有自己的理解和规定(不同版本可能也不一样).
            例如++j, i++都是在 i += j; 之前完成, 而且产生副作用. 这时 i+= j; 后 i 的值是 5. 第一个 i 也是 5.

如果你用 Borland-C++  结果可能又不一样. 别纠结了.

出0入93汤圆

发表于 2013-4-26 09:34:00 | 显示全部楼层
小德GD 发表于 2013-4-26 00:46
但用VC6.0测确实是4,4,4,3

又是一个深受谭浩强毒害的……你已经发现这个是坑了,为什么还要往里跳?C语言的陷阱防不胜防的。
主要原因为未定义行为

第一个为什么结果是2,2,1?因为依赖编译器实现,结果还可以是2,2,2。把++放到i后面,你的结论还会更不同。第二个同理。不信请用VC Debug/Release模式分别都试试。
因此,我们要尽量避免编译器的未定义行为,进到坑了尽量绕道,别一脚踏进去了。

出0入0汤圆

发表于 2013-4-26 12:34:34 | 显示全部楼层
小德GD 发表于 2013-4-26 00:44
如果按照printf从右到左的顺序的话,我想也是5,4,4,3,但我用VC6.0是4,4,4,3

我用C_FREE编的,看来不同的编译器也有不同结果

出0入0汤圆

 楼主| 发表于 2013-4-26 12:56:33 | 显示全部楼层
monkerman 发表于 2013-4-26 08:59
唉......VC 的结果既然是这样, 我就给解释下吧.
首先从右往左:
++j 后 j 变成了 3, 注意前加操作是先自 ...

非常谢谢你用心的回答。想再麻烦问下“i, 当然也是 4, 因为 , 号不是序列点.”这句话怎么理解?

出0入0汤圆

 楼主| 发表于 2013-4-26 13:12:40 | 显示全部楼层
takashiki 发表于 2013-4-26 09:34
又是一个深受谭浩强毒害的……你已经发现这个是坑了,为什么还要往里跳?C语言的陷阱防不胜防的。
主要原 ...

恩,受教了,谢谢

出0入0汤圆

发表于 2013-4-26 13:35:43 | 显示全部楼层
本帖最后由 monkerman 于 2013-4-26 13:51 编辑
小德GD 发表于 2013-4-26 12:56
非常谢谢你用心的回答。想再麻烦问下“i, 当然也是 4, 因为 , 号不是序列点.”这句话怎么理解? ...


不客气. 我也只是恰好知道.
第一个 i 的值其实是第二个 i++ 的 i 值, 因为 VC 对后加操作的自增是在语句结束之后, 也就是分号. 所以还是 4, 逗号在这里并不被当作是序列点.
剩下的上面已经解释了. 你可以改一下, 然后再看结果. 多来几次可能就明白了. 强烈建议比看反汇编, 看到 incl 指令就明白了.
例如:
  1. printf("%d, %d, %d, %d", i++, i++, i += j++, ++j); // 看一下结果, 测试时可以这么写, 正式时千万别这么写, 会被骂的.
复制代码

出0入0汤圆

发表于 2013-4-26 13:43:24 | 显示全部楼层
看来是一个学生
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 16:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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