矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 1771|回复: 20

请教51大佬

[复制链接]
     
发表于 2022-9-16 10:48:20 | 显示全部楼层 |阅读模式
v=(P3>>4)&1;
v=P3&(1<<4)>0;
这两个代码啥区别,为啥上面的不起作用
按照C语言的位理解他们应该等效才对
     
发表于 2022-9-16 11:02:11 | 显示全部楼层
你用手一步一步画一下,一样吗?
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 11:08:25 | 显示全部楼层
ssffzz1 发表于 2022-9-16 11:02
你用手一步一步画一下,一样吗?

一样啊,我都已经Python和C-Free来论证了
会不会因为P3这种端口,不允许被完全读出来的原因,只允许&|^操作它的位
回复 支持 反对

使用道具 举报

     
发表于 2022-9-16 11:13:08 | 显示全部楼层
本帖最后由 ssffzz1 于 2022-9-16 11:38 编辑
JuncoJet 发表于 2022-9-16 11:08
一样啊,我都已经Python和C-Free来论证了
会不会因为P3这种端口,不允许被完全读出来的原因,只允许&|^ ...


你是如何论证的呢?
最好有个过程

我目测分析下:

'
v=(P3>>4)&1;
'
P3先 右移  4位 ,再和1做  &  操作 ,这个时候P3只能是1,没有其他可能,你前面移位多少无所谓,你最后出来都是V=1。

补充:“你前面移位多少无所谓”,这句话错了,不是无所谓,还是看 & 结果。

'
v=P3&(1<<4)>0;
'
这个是1先左移 4 ,出来就是 0b1000  ,这个值和 P3 左  & 操作,出来了的值就是 0b1000(十进制16),而和P3原来是什么值没有任何关系。

补充:“而和P3原来是什么值没有任何关系”,这句话错了,不是无所谓,还是看 & 结果。

补充:
>0 ,这个我没看,我是觉着你写错了,所以没分析,加入>0后,有点不同,需要我再看看。

还是看10楼的分析吧,那个对的。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 11:17:17 | 显示全部楼层
本帖最后由 JuncoJet 于 2022-9-16 11:20 编辑
ssffzz1 发表于 2022-9-16 11:13
你是如何论证的呢?
最好有个过程

  1. >>> P3=0
  2. >>> P3>>4
  3. 0
  4. >>> P3=0x10
  5. >>> P3>>4
  6. 1
  7. >>> P3&(1<<4)
  8. 16
  9. >>> P3&(1<<4)>0
  10. True
  11. >>> P3>>4&1
  12. 1
  13. >>> P3=0x111
  14. >>> P3&(1<<4)>0
  15. True
  16. >>> P3>>4&1
  17. 1
  18. >>> P3=0xFF
  19. >>> P3>>4
  20. 15
  21. >>> P3>>4&1
  22. 1
  23. >>> P3&(1<<4)
  24. 16
  25. >>> P3&(1<<4)>0
  26. True
复制代码
回复 支持 反对

使用道具 举报

     
发表于 2022-9-16 11:20:33 | 显示全部楼层


c是c,py是py,你这个先不混一块单独看。

回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 11:22:46 | 显示全部楼层
ssffzz1 发表于 2022-9-16 11:20
c是c,py是py,你这个先不混一块单独看。

Image 854.jpg
Image 855.jpg
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 11:25:55 | 显示全部楼层
Image 857.jpg
Image 856.jpg
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 11:30:46 | 显示全部楼层
本帖最后由 JuncoJet 于 2022-9-16 11:36 编辑

好像确实哪里不太对
补上括号他们的作用就一样了,完了烧写到CH552G上都不翻转
Image 856.jpg
Image 854.jpg
Image 855.jpg
回复 支持 反对

使用道具 举报

     
发表于 2022-9-16 11:36:32 | 显示全部楼层
本帖最后由 ssffzz1 于 2022-9-16 11:40 编辑

1、第一步,我写个C代码试试
  1. #include <stdio.h>

  2. int
  3. main(void)
  4. {
  5.     unsigned int v1,v2;
  6.     unsigned int P3=0x5a5a5a5a;

  7.     printf("P3=%#x\n",P3);
  8.    
  9.     v1=(P3>>4)&1;
  10.     v2=P3&(1<<4)>0;

  11.     printf("v1=%#x\n",v1);
  12.     printf("v2=%#x\n",v2);

  13.     return(0);
  14. }
复制代码


2、编译测试过程如下
  1. C20X~/tmp$ gcc -Wall -o 1 1.c
  2. 1.c: In function ‘main’:
  3. 1.c:12:10: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
  4.      v2=P3&(1<<4)>0;
  5.           ^
  6. C20X~/tmp$ ./1
  7. P3=0x5a5a5a5a
  8. v1=0x1
  9. v2=0
  10. C20X~/tmp$
复制代码


这个warning的意思就是12行这个表达是写的不够清晰,希望你弄个括号上去写明白点的意思。

3、汇编代码分析
  1. # 函数序言,不管它
  2.     1135:        55                           push   %rbp
  3.     1136:        48 89 e5                     mov    %rsp,%rbp
  4.     1139:        48 83 ec 10                  sub    $0x10,%rsp

  5. # unsigned int P3=0x5a5a5a5a; ,rbp-0x4这个位置是P3变量
  6.     113d:        c7 45 fc 5a 5a 5a 5a         movl   $0x5a5a5a5a,-0x4(%rbp)

  7. # printf("P3=%#x\n",P3);
  8.     1144:        8b 45 fc                     mov    -0x4(%rbp),%eax
  9.     1147:        89 c6                        mov    %eax,%esi
  10.     1149:        48 8d 3d b4 0e 00 00         lea    0xeb4(%rip),%rdi        # 2004 <_IO_stdin_used+0x4>
  11.     1150:        b8 00 00 00 00               mov    $0x0,%eax
  12.     1155:        e8 d6 fe ff ff               callq  1030 <printf@plt>


  13. [color=Red]# P3进%eax寄存器   
  14.     115a:        8b 45 fc                     mov    -0x4(%rbp),%eax
  15. # %eax寄存器里的值右移 4位
  16.     115d:        c1 e8 04                     shr    $0x4,%eax
  17. # 再和1做与运算
  18.     1160:        83 e0 01                     and    $0x1,%eax
  19. # 保存到v1,v1变量的位置是-0x8(%rbp)
  20.     1163:        89 45 f8                     mov    %eax,-0x8(%rbp)

  21. # P3进%eax寄存器   
  22.     1166:        8b 45 fc                     mov    -0x4(%rbp),%eax
  23. # %eax直接和 1 做了 and
  24.     1169:        83 e0 01                     and    $0x1,%eax
  25. # 保存到V2变量,v1变量的位置是-0xc(%rbp)
  26.     116c:        89 45 f4                     mov    %eax,-0xc(%rbp)
  27. [/color]
  28.     116f:        8b 45 f8                     mov    -0x8(%rbp),%eax
  29.     1172:        89 c6                        mov    %eax,%esi
  30.     1174:        48 8d 3d 91 0e 00 00         lea    0xe91(%rip),%rdi        # 200c <_IO_stdin_used+0xc>
  31.     117b:        b8 00 00 00 00               mov    $0x0,%eax
  32.     1180:        e8 ab fe ff ff               callq  1030 <printf@plt>

  33.     1185:        8b 45 f4                     mov    -0xc(%rbp),%eax
  34.     1188:        89 c6                        mov    %eax,%esi
  35.     118a:        48 8d 3d 83 0e 00 00         lea    0xe83(%rip),%rdi        # 2014 <_IO_stdin_used+0x14>
  36.     1191:        b8 00 00 00 00               mov    $0x0,%eax
  37.     1196:        e8 95 fe ff ff               callq  1030 <printf@plt>

  38. # return 0
  39.     119b:        b8 00 00 00 00               mov    $0x0,%eax
  40.     11a0:        c9                           leaveq
  41.     11a1:        c3                           retq   

复制代码


# P3进%eax寄存器   
    115a:        8b 45 fc                     mov    -0x4(%rbp),%eax
# %eax寄存器里的值右移 4位
    115d:        c1 e8 04                     shr    $0x4,%eax
# 再和1做与运算
    1160:        83 e0 01                     and    $0x1,%eax
# 保存到v1,v1变量的位置是-0x8(%rbp)
    1163:        89 45 f8                     mov    %eax,-0x8(%rbp)

# P3进%eax寄存器   
    1166:        8b 45 fc                     mov    -0x4(%rbp),%eax
# %eax直接和 1 做了 and
    1169:        83 e0 01                     and    $0x1,%eax
# 保存到V2变量,v1变量的位置是-0xc(%rbp)
    116c:        89 45 f4                     mov    %eax,-0xc(%rbp)


着重看后半段红字,那个是v2那个表达式的真正汇编代码,这里没有看到 (1<<4)&0的具体执行,那是因为 编译器给你算好了。
(1) 1<<4 ,测出来是 16
(2) 16 > 0,因此结果为真,在这个版本的C语言里用1表示
就是这句 1169:        83 e0 01                     and    $0x1,%eax

最后就是P3和1与的结果了。

4、这里为什么v2是0呢,因为那个5a,的第0位是0,我换个数值试试

  1. C20X~/tmp$ cat 1.c
  2. #include <stdio.h>

  3. int
  4. main(void)
  5. {
  6.     unsigned int v1,v2;
  7.     unsigned int P3=0x5a5a5a55;

  8.     printf("P3=%#x\n",P3);
  9.    
  10.     v1=(P3>>4)&1;
  11.     v2=P3&(1<<4)>0;

  12.     printf("v1=%#x\n",v1);
  13.     printf("v2=%#x\n",v2);

  14.     return(0);
  15. }

  16. C20X~/tmp$ gcc -Wall -o 1 1.c
  17. 1.c: In function ‘main’:
  18. 1.c:12:10: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
  19.      v2=P3&(1<<4)>0;
  20.           ^
  21. C20X~/tmp$ ./1
  22. P3=0x5a5a5a55
  23. v1=0x1
  24. v2=0x1
  25. C20X~/tmp$
复制代码
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 12:23:16 | 显示全部楼层
ssffzz1 发表于 2022-9-16 11:36
1、第一步,我写个C代码试试

现在诊断出是什么问题了
P3&=~(1<<4);
这个的问题,CH552上这个效果等同于^,会自动翻转

for(;;){
        P3&=~(1<<4);
        mDelaymS(1000);
}
这才是诡异的点
回复 支持 反对

使用道具 举报

     
发表于 2022-9-16 13:52:30 | 显示全部楼层
JuncoJet 发表于 2022-9-16 12:23
现在诊断出是什么问题了
P3&=~(1


我没仔细看你的那几张截图的代码,

不过就这句来看:
P3&=~(1<<4);

假设他们是unsigned char 吧

(1)1 << 4 的结果是 0b 00010000

(2)再取反就是0b11101111

(3) P3的值和上面的做与运算,简单的说就是第4个bit清零。


如果你得到的结果和预想不一致,那么最简单的方法是去看看汇编代码,哪里最直接,没有C这么多弯弯绕。
最后c-free我还真不熟悉,小众的编译器有bug也是有可能的。还是看汇编代码就能发现。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 14:19:08 | 显示全部楼层
ssffzz1 发表于 2022-9-16 13:52
我没仔细看你的那几张截图的代码,

不过就这句来看:

网上有人说看门狗的问题导致被重置,我注释掉Init();代码能正常跑了
回复 支持 反对

使用道具 举报

     
发表于 2022-9-16 14:53:25 | 显示全部楼层
后面那个>0是笔误吗?
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-9-16 15:06:31 | 显示全部楼层
world_all 发表于 2022-9-16 14:53
后面那个>0是笔误吗?

不是笔误 >0 得到布尔值
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-7 08:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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