鱼C论坛

 找回密码
 立即注册
查看: 2264|回复: 12

[已解决]问一个关于自增,自减与printf 的问题请大家深入思考在答复

[复制链接]
发表于 2019-3-25 13:00:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. #include<stdio.h>

  2. int main()
  3. {
  4.     int x=5;//在我的编译器上得到的结果6 5
  5.     printf("%d\n%d\n",x,x++);
  6.    
  7.     x=5;//在我的编译器上得到的结果6 6
  8.     printf("\n%d\n%d\n",x,++x);
  9.    
  10.     x=5;//在我的编译器上得到的结果5 6
  11.     printf("\n%d\n%d\n",x++,x);
  12.    
  13.     x=5;//在我的编译器上得到的结果6 6
  14.     printf("\n%d\n%d\n",++x,x);
  15.    
  16.     x=5;//在我的编译器上得到的结果5 5
  17.     printf("\n%d\n%d\n",++x,--x);
  18.    
  19.     x=5;//在我的编译器上得到的结果5 5
  20.     printf("\n%d\n%d\n",--x,++x);
  21.    
  22.     x=5;//在我的编译器上得到的结果4 5
  23.     printf("\n%d\n%d\n",x++,x--);
  24.    
  25.     x=5;//在我的编译器上得到的结果6 5
  26.     printf("\n%d\n%d\n",x--,x++);
  27.     getchar();
  28.     return 0;
  29. }
复制代码

第一个X 为什么是6
第三个X++为什么是5
最佳答案
2019-3-25 17:31:54
本帖最后由 Croper 于 2019-3-25 17:34 编辑

这个问题已经是周经问题了。。。。
再说一下,关于在同一个表达式\函数参数中连续使用++或--,这种用法最终结果是编译器相关的,
不规范而且没有讨论的意义(在C语言的角度而言);
如果一定要弄懂请反汇编

你的代码太长,举个短点的例子

  1. int i=0;       
  2. printf("%d\ %d\ %d\ %d", ++i, --i, i++, i--);
  3. 00007FF67F481931  mov         eax,dword ptr [i]  
  4. 00007FF67F481934  mov         dword ptr [rbp+0D4h],eax  
  5. 00007FF67F48193A  mov         eax,dword ptr [i]  
  6. 00007FF67F48193D  dec         eax  
  7. 00007FF67F48193F  mov         dword ptr [i],eax  
  8. 00007FF67F481942  mov         eax,dword ptr [i]  
  9. 00007FF67F481945  mov         dword ptr [rbp+0D8h],eax  
  10. 00007FF67F48194B  mov         eax,dword ptr [i]  
  11. 00007FF67F48194E  inc         eax  
  12. 00007FF67F481950  mov         dword ptr [i],eax  
  13. 00007FF67F481953  mov         eax,dword ptr [i]  
  14. 00007FF67F481956  dec         eax  
  15. 00007FF67F481958  mov         dword ptr [i],eax  
  16. 00007FF67F48195B  mov         eax,dword ptr [i]  
  17. 00007FF67F48195E  inc         eax  
  18. 00007FF67F481960  mov         dword ptr [i],eax  
  19. 00007FF67F481963  mov         eax,dword ptr [rbp+0D4h]  
  20. 00007FF67F481969  mov         dword ptr [rsp+20h],eax  
  21. 00007FF67F48196D  mov         r9d,dword ptr [rbp+0D8h]  
  22. 00007FF67F481974  mov         r8d,dword ptr [i]  
  23. 00007FF67F481978  mov         edx,dword ptr [i]  
  24. 00007FF67F48197B  lea         rcx,[string "%d %d %d %d" (07FF67F489C28h)]  
  25. 00007FF67F481982  call        printf (07FF67F4811D6h)  
复制代码

以上是在VS2017下反汇编的结果,
可以看到,后置++,--是储存在了临时变量ptr [rbp+0D8h],[rbp+0D4h]中,而前置++,--是直接使用的原变量,

所以最终的结果是0 0 -1 0;
而这个结果从C语言的角度怎么分析都是乱的

另外,看了下楼主之前发的主体贴,建议先学习Window程序设计,弄懂gdi已经能做很多漂亮的图形界面了,
然后可以学习directX或Opengl,一步一步来,不要好高骛远

另外,送楼主一句话:

思而不学则殆

评分

参与人数 1荣誉 +2 鱼币 +3 贡献 +3 收起 理由
RIXO + 2 + 3 + 3 虽然大佬们觉得没啥意义,但我感觉对我这样.

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-25 14:23:23 From FishC Mobile | 显示全部楼层
早就被废弃的课题了,现在还有人研究
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-25 16:15:36 | 显示全部楼层
这种问题没意义,反汇编查看汇编代码就知道了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-25 17:31:54 | 显示全部楼层    本楼为最佳答案   
本帖最后由 Croper 于 2019-3-25 17:34 编辑

这个问题已经是周经问题了。。。。
再说一下,关于在同一个表达式\函数参数中连续使用++或--,这种用法最终结果是编译器相关的,
不规范而且没有讨论的意义(在C语言的角度而言);
如果一定要弄懂请反汇编

你的代码太长,举个短点的例子

  1. int i=0;       
  2. printf("%d\ %d\ %d\ %d", ++i, --i, i++, i--);
  3. 00007FF67F481931  mov         eax,dword ptr [i]  
  4. 00007FF67F481934  mov         dword ptr [rbp+0D4h],eax  
  5. 00007FF67F48193A  mov         eax,dword ptr [i]  
  6. 00007FF67F48193D  dec         eax  
  7. 00007FF67F48193F  mov         dword ptr [i],eax  
  8. 00007FF67F481942  mov         eax,dword ptr [i]  
  9. 00007FF67F481945  mov         dword ptr [rbp+0D8h],eax  
  10. 00007FF67F48194B  mov         eax,dword ptr [i]  
  11. 00007FF67F48194E  inc         eax  
  12. 00007FF67F481950  mov         dword ptr [i],eax  
  13. 00007FF67F481953  mov         eax,dword ptr [i]  
  14. 00007FF67F481956  dec         eax  
  15. 00007FF67F481958  mov         dword ptr [i],eax  
  16. 00007FF67F48195B  mov         eax,dword ptr [i]  
  17. 00007FF67F48195E  inc         eax  
  18. 00007FF67F481960  mov         dword ptr [i],eax  
  19. 00007FF67F481963  mov         eax,dword ptr [rbp+0D4h]  
  20. 00007FF67F481969  mov         dword ptr [rsp+20h],eax  
  21. 00007FF67F48196D  mov         r9d,dword ptr [rbp+0D8h]  
  22. 00007FF67F481974  mov         r8d,dword ptr [i]  
  23. 00007FF67F481978  mov         edx,dword ptr [i]  
  24. 00007FF67F48197B  lea         rcx,[string "%d %d %d %d" (07FF67F489C28h)]  
  25. 00007FF67F481982  call        printf (07FF67F4811D6h)  
复制代码

以上是在VS2017下反汇编的结果,
可以看到,后置++,--是储存在了临时变量ptr [rbp+0D8h],[rbp+0D4h]中,而前置++,--是直接使用的原变量,

所以最终的结果是0 0 -1 0;
而这个结果从C语言的角度怎么分析都是乱的

另外,看了下楼主之前发的主体贴,建议先学习Window程序设计,弄懂gdi已经能做很多漂亮的图形界面了,
然后可以学习directX或Opengl,一步一步来,不要好高骛远

另外,送楼主一句话:

思而不学则殆
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2019-3-25 18:02:42 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-3-25 22:15:47 | 显示全部楼层
Croper 发表于 2019-3-25 17:31
这个问题已经是周经问题了。。。。
再说一下,关于在同一个表达式\函数参数中连续使用++或--,这种用法最 ...

同学问我的问题  然后就搞成代码,结果自己给人家解释不了,所以跑来问大家  谢谢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 10:59:02 | 显示全部楼层
本帖最后由 wwhywhy 于 2019-4-20 12:06 编辑

这个值是跟编译器无关的。
printf()函数的使用参数的顺序是从右到左。按照这个顺序,你就能得到计算机给你的结果。你再看看。

这种的使用方法如果还能出现不确定性,你觉得C或者C++还有存在的必要么?我们在工程上还怎么敢用C和C++啊?

不要那么简单的下决定,创建C或者C++的人那么牛。编写编译器的人也非常的厉害。怎么会出现这种低级的问题呢?

我认为出现不理解的地方,应该是我们自己的问题。没有理解透。
你说呢?


有个简单的计算方法:
printf中的只要是前置的,所有值都是一样的(是最终的变量的值)。后置的变量需要逐个计算就可以了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 13:21:07 | 显示全部楼层
本帖最后由 Croper 于 2019-4-20 13:51 编辑
wwhywhy 发表于 2019-4-20 10:48
这个值是跟编译器无关的。


请问你是凭什么说这句话的?
不然你来解释一下,编译器都不用换,不同的生成选项都能出不同的结果:

                               
登录/注册后可看大图


                               
登录/注册后可看大图


这是stackoverflow上的相关讨论
https://stackoverflow.com/questions/1270370/printfd-d-d-n-a-a-a-output
C has the concept of undefined behavior, i.e. some language constructs are syntactically valid but you can't predict the behavior when the code is run.

As far as I know, the standard doesn't explicitly say why the concept of undefined behavior exists. In my mind, it's simply because the language designers wanted there to be some leeway in the semantics, instead of i.e. requiring that all implementations handle integer overflow in the exact same way, which would very likely impose serious performance costs, they just left the behavior undefined so that if you write code that causes integer overflow, anything can happen.

So, with that in mind, why are these "issues"? The language clearly says that certain things lead to undefined behavior. There is no problem, there is no "should" involved. If the undefined behavior changes when one of the involved variables is declared volatile, that doesn't prove or change anything. It is undefined; you cannot reason about the behavior.


不懂的问题不要想当然
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 23:18:33 | 显示全部楼层
本帖最后由 wwhywhy 于 2019-4-20 23:41 编辑

你的这个贴图: release版的理解不了。
我手边没有vs。能解释下么?
根本的还是vs如何做的优化吧?。。。
很好奇
我手里只有codeblocks 在这个环境下,两种情况都是一样的。你的竟然不一样?同样的东西,两种结果,怎么想都不太对劲啊。

我承认,我手边的环境只有win,我的判断还是武断了些。但是你的结果也太不可思议了吧?
你给我的链接里都是是在讨论,以及解释。但是也没有到你这种状态:同一个编译器,优化前后的结果都不一样。
(你给的英文是跟本问题相关的吗?)
我建议你再确认下release版的 结果好么?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 23:42:17 | 显示全部楼层
反汇编了一下,结果我也无法理解,似乎编译器在编译期间直接算出了结果,
然而我并不会拆编译器在编译期间是如何计算的。。。
  1.         int i = 10;
  2.         printf("%d %d %d", ++i, i++, i);
  3. 00161040  push        0Bh  
  4. 00161042  push        0Ah  
  5. 00161044  push        0Bh  
  6. 00161046  push        offset string "%d %d %d" (01620F8h)  
  7. 0016104B  call        printf (0161010h)
复制代码

这里直接push的就是11 10 11,具体为什么是这样完全不知道

我觉得还是不要纠结这种东西,既然已经明确了是未定义的行为,那么出现什么结果都有可能,
work in ways you could never understand, crash, blow up, or if it's feeling particularly witty, send nasty emails to your mother

send nasty emails to your mother 233333.....
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 23:56:04 | 显示全部楼层
你给的英文是跟本问题相关的吗?

确实不是那个链接里的,不过是同样的问题
https://stackoverflow.com/questi ... -undefined-behavior
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-21 19:29:00 | 显示全部楼层
本帖最后由 wwhywhy 于 2019-4-21 19:35 编辑
Croper 发表于 2019-4-20 23:56
确实不是那个链接里的,不过是同样的问题
https://stackoverflow.com/questions/949433/why-are-these-c ...


你可真厉害!随随便便就找了这么多的资源。我也顺便学习了好多。(网站我也收藏了。)
其实我也明白你说的提醒:不必过多纠缠。不过你后面的红字,又提示我还是要多多的思考和探究。
毕竟别人的结论是别人的,经过自己的思考和推演才是自己的。
所以才在明知道已经有结果的情况下,又追问了几次。
非常非常的感谢你! :)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-21 19:33:42 | 显示全部楼层
Croper 发表于 2019-4-20 23:42
反汇编了一下,结果我也无法理解,似乎编译器在编译期间直接算出了结果,
然而我并不会拆编译器在编译期间 ...

以前我用vs的时候也会出现这种问题。隐约记得先做clear之后,再重新编译就OK了。
好像是什么东西没有清干净似的。不过,从来没有用反汇编探究过。
谢谢啦。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-20 02:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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