鱼C论坛

 找回密码
 立即注册
查看: 1152|回复: 8

[已解决]这个逻辑与运算是怎样优化的 求告知 感谢!

[复制链接]
发表于 2018-10-26 09:40:21 | 显示全部楼层 |阅读模式

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

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

x

   RT:
#include<stdio.h>
void main()
{
        int a=0,b=2,c;
        c=!a||++b&&a--;
        printf("%d,%d,%d\n",a,b,c);
}

结果:0,2,1

上面是编译器运行的结果
但是 我觉得 结果应该是:a=-1,b=3,c=1
所以有点不明白 与运算和自增自减 在这里是怎么优化的
希望各位鱼油指教,谢谢!
最佳答案
2018-10-26 15:05:46
//为了回答这道题,以下以C注释形式分析以下汇编代码
#include<stdio.h>
void main()
{
010F13C0  push        ebp  
010F13C1  mov         ebp,esp  
010F13C3  sub         esp,0E8h  
010F13C9  push        ebx  
010F13CA  push        esi  
010F13CB  push        edi  
010F13CC  lea         edi,[ebp-0E8h]  
010F13D2  mov         ecx,3Ah  
010F13D7  mov         eax,0CCCCCCCCh  
010F13DC  rep stos    dword ptr es:[edi]  
        int a = 0, b = 2, c;
010F13DE  mov         dword ptr [a],0  
010F13E5  mov         dword ptr [b],2  
//以上代码与问题无关不做解释
//------------------------------------------完美分割线--------------------------------------
        c = !a || ++b && a--;
//以下两句为!a计算并实现||运算符的短路原则
010F13EC  cmp         dword ptr [a],0                  //将a与0比较
010F13F0  je          main+59h (010F1419h)         //a为0则跳到地址010F1419h处,其实这里就直接跳转了,从这道010F1419h代码都没执行

//以下三句为++b实现代码
010F13F2  mov         eax,dword ptr [b]          //将b内存中的值移动到寄存器eax中
010F13F5  add         eax,1                          //eax寄存器自加1
010F13F8  mov         dword ptr [b],eax          //将eax的值移动回到b内存处

//当b为0则跳到010F140Dh处,不为0则继续
010F13FB  je          main+4Dh (010F140Dh)  

//以下四句位为a--对应代码
010F13FD  mov         ecx,dword ptr [a]          //a移动到ecx寄存器(备份a的值,以便后序判断使用)
010F1400  mov         edx,dword ptr [a]          //a移动到edx寄存器
010F1403  sub         edx,1                          //edx-1
010F1406  mov         dword ptr [a],edx          //将edx存会a

//ecx为刚才对a的备份,以下一句测试原来的a值是否为0,也就是实现后 -- 的先使用后自减的特性
010F1409  test        ecx,ecx  
010F140B  jne         main+59h (010F1419h)  //原a不为0则表示逻辑与 && 成立, 跳到010F1419h

//原a为0则逻辑与表达式为假
010F140D  mov         dword ptr [ebp-0E8h],0                  //用一个临时变量来存放记过(ebp-0E8h)
010F1417  jmp         main+63h (010F1423h)                  //跳到010F1423h处

//原a不为0则表达式为真将1赋值到临时变量
010F1419  mov         dword ptr [ebp-0E8h],1

//将临时变量赋值个c变量
010F1423  mov         eax,dword ptr [ebp-0E8h]  
010F1429  mov         dword ptr [c],eax

//以下调用printf函数,不做解释
//---------------------------------------------完美分割线再现----------------------------------------
        printf("%d,%d,%d\n", a, b, c);
010F142C  mov         esi,esp  
010F142E  mov         eax,dword ptr [c]  
010F1431  push        eax  
010F1432  mov         ecx,dword ptr [b]  
010F1435  push        ecx  
010F1436  mov         edx,dword ptr [a]  
010F1439  push        edx  
010F143A  push        10F5858h  
010F143F  call        dword ptr ds:[10F9114h]  
010F1445  add         esp,10h  
010F1448  cmp         esi,esp  
010F144A  call        __RTC_CheckEsp (010F1136h)          //堆栈平衡检测
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-10-26 09:49:42 | 显示全部楼层
为什么b不自增呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-10-26 09:56:46 | 显示全部楼层
本帖最后由 pheron 于 2018-10-26 10:22 编辑

我觉得楼下说的对
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-10-26 10:02:43 | 显示全部楼层
本帖最后由 风扫地 于 2018-10-27 08:59 编辑

可能和短路原则有关。
因为你的 !a||++b&&a--  代码里面没括号,我不熟悉结合关系和计算顺序(学的时候弄明白就行,因为考试肯定要考,但确实很难记住那么多运算符的结合顺序和优先级,在工作工程中必须用小括号明确运算结合关系和运算顺序),不具体分析。
短路原则是指:
对于 &&  || 这两个运算符,
若 a && b 中的a已经为0,b就不算了,因为0 && x = 0
若 a || b 中的a已经为1,b就不算了,因为 1 || x = 1



Ref:
https://bbs.csdn.net/topics/190096722
https://fishc.com.cn/forum.php?m ... hlight=%B6%CC%C2%B7
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-10-26 10:24:56 | 显示全部楼层
嗷嗷记起来了
&&和||语句的判断都是从左至右的。
即a && b会先判断a,如果a为True,则还需要判断b的Boolean值,不管b的Boolean值是什么,最后一个判断的是b,所以会输出b的Boolean值;反之,如果a为False,则不需要再判断b的Boolean值了,因为结果肯定为False,所以最后进行判断的就是a,也就是会输出a的Boolean值。
而a || b也是会先判断a,如果a的Boolean值为True,则不需要再判断b的Boolean值了,因为结果肯定是True了,也就是会输出a的Boolean值;如果a的Boolean值为False,则就需要再去判断b的Boolean值,不管b的Boolean值为多少,最后进行判断的都是b,也就是输出就为b的Boolean值。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-10-26 15:05:46 | 显示全部楼层    本楼为最佳答案   
//为了回答这道题,以下以C注释形式分析以下汇编代码
#include<stdio.h>
void main()
{
010F13C0  push        ebp  
010F13C1  mov         ebp,esp  
010F13C3  sub         esp,0E8h  
010F13C9  push        ebx  
010F13CA  push        esi  
010F13CB  push        edi  
010F13CC  lea         edi,[ebp-0E8h]  
010F13D2  mov         ecx,3Ah  
010F13D7  mov         eax,0CCCCCCCCh  
010F13DC  rep stos    dword ptr es:[edi]  
        int a = 0, b = 2, c;
010F13DE  mov         dword ptr [a],0  
010F13E5  mov         dword ptr [b],2  
//以上代码与问题无关不做解释
//------------------------------------------完美分割线--------------------------------------
        c = !a || ++b && a--;
//以下两句为!a计算并实现||运算符的短路原则
010F13EC  cmp         dword ptr [a],0                  //将a与0比较
010F13F0  je          main+59h (010F1419h)         //a为0则跳到地址010F1419h处,其实这里就直接跳转了,从这道010F1419h代码都没执行

//以下三句为++b实现代码
010F13F2  mov         eax,dword ptr [b]          //将b内存中的值移动到寄存器eax中
010F13F5  add         eax,1                          //eax寄存器自加1
010F13F8  mov         dword ptr [b],eax          //将eax的值移动回到b内存处

//当b为0则跳到010F140Dh处,不为0则继续
010F13FB  je          main+4Dh (010F140Dh)  

//以下四句位为a--对应代码
010F13FD  mov         ecx,dword ptr [a]          //a移动到ecx寄存器(备份a的值,以便后序判断使用)
010F1400  mov         edx,dword ptr [a]          //a移动到edx寄存器
010F1403  sub         edx,1                          //edx-1
010F1406  mov         dword ptr [a],edx          //将edx存会a

//ecx为刚才对a的备份,以下一句测试原来的a值是否为0,也就是实现后 -- 的先使用后自减的特性
010F1409  test        ecx,ecx  
010F140B  jne         main+59h (010F1419h)  //原a不为0则表示逻辑与 && 成立, 跳到010F1419h

//原a为0则逻辑与表达式为假
010F140D  mov         dword ptr [ebp-0E8h],0                  //用一个临时变量来存放记过(ebp-0E8h)
010F1417  jmp         main+63h (010F1423h)                  //跳到010F1423h处

//原a不为0则表达式为真将1赋值到临时变量
010F1419  mov         dword ptr [ebp-0E8h],1

//将临时变量赋值个c变量
010F1423  mov         eax,dword ptr [ebp-0E8h]  
010F1429  mov         dword ptr [c],eax

//以下调用printf函数,不做解释
//---------------------------------------------完美分割线再现----------------------------------------
        printf("%d,%d,%d\n", a, b, c);
010F142C  mov         esi,esp  
010F142E  mov         eax,dword ptr [c]  
010F1431  push        eax  
010F1432  mov         ecx,dword ptr [b]  
010F1435  push        ecx  
010F1436  mov         edx,dword ptr [a]  
010F1439  push        edx  
010F143A  push        10F5858h  
010F143F  call        dword ptr ds:[10F9114h]  
010F1445  add         esp,10h  
010F1448  cmp         esi,esp  
010F144A  call        __RTC_CheckEsp (010F1136h)          //堆栈平衡检测
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-10-27 05:24:42 From FishC Mobile | 显示全部楼层
因为!a一定为真,所以||后面的代码都不执行了,好像是叫短路原则
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-10-27 10:10:08 | 显示全部楼层
短路原则,竟然这么神奇!又学习了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-10-27 11:47:58 From FishC Mobile | 显示全部楼层
在这里谢过各位鱼油了 么么哒
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-10-2 20:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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