搜索
bottom↓
回复: 31

三个8位无符号数拼成一个24位数,这样移位拼怎么会错

[复制链接]

出0入12汤圆

发表于 2019-2-19 11:53:36 | 显示全部楼层 |阅读模式
ulong k;
uchar j;

j=0x55;
k=j<<16;
j=0xAA;
k+=(j<<8);
j=0x33;
k+=j;       
得出的结果k为0xFFAA33

改成
j=0x55;
k=((ulong)j)<<16;
j=0xAA;
k+=(j<<8);
j=0x33;
k+=j;
得出的结果k为0x54AA33

用以下的方法就能得出正确结果k=0x55AA33

j=0x55;
k=j<<8;
j=0xAA;
k+=j;
k=k<<8;
j=0x33;
k+=j;

编译软件iccavr8。这是怎么回事?

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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2019-2-19 11:58:12 | 显示全部楼层
uchar j;
k=j<<16;

定义小了, 舍不得内存开销,哪能抓野猪

出130入129汤圆

发表于 2019-2-19 11:58:18 | 显示全部楼层
j是8位的,移那么多位可以吗?

出0入0汤圆

发表于 2019-2-19 11:59:15 | 显示全部楼层
小女子要嫁高富帅, 自己也要花点内存 打扮打扮

出0入0汤圆

发表于 2019-2-19 12:11:57 | 显示全部楼层
移位出问题,基本都是数据类型转换中出的错误

出0入442汤圆

发表于 2019-2-19 12:12:48 来自手机 | 显示全部楼层
自己查汇编吧。编译器出错的几率是存在的。通常约定编译器执行时以最大的数据类型为准。

出0入442汤圆

发表于 2019-2-19 12:14:40 来自手机 | 显示全部楼层
对了,avr在gcc8.2.0下编译,当大于6kb时,加一堆编译指令禁用jumptable也经常给我生成不可理喻的结果。所以我已经不再用avr了。目前用riscv,没出过任何故障。

出0入0汤圆

发表于 2019-2-19 12:27:57 | 显示全部楼层
定义联合,然后直接赋值更简单高效吧。

出0入0汤圆

发表于 2019-2-19 13:04:06 | 显示全部楼层
我记得以前参加笔试的时候经常遇到类似的题目。

出0入0汤圆

发表于 2019-2-19 13:22:02 来自手机 | 显示全部楼层
wye11083 发表于 2019-2-19 12:14
对了,avr在gcc8.2.0下编译,当大于6kb时,加一堆编译指令禁用jumptable也经常给我生成不可理喻的结果。所 ...

求问RISC V有推荐的芯片吗,好像平常没见到过呢

出0入442汤圆

发表于 2019-2-19 13:49:56 来自手机 | 显示全部楼层
fnems 发表于 2019-2-19 13:22
求问RISC V有推荐的芯片吗,好像平常没见到过呢

我是fpga软核。riscv目前还没有。你可以考虑stm32。arm,x86,riscv还是比较稳定的。mips有段时间编译器也犯傻,一个好好的switch case结果汇编里面丢了一个case。

出0入475汤圆

发表于 2019-2-19 13:52:11 来自手机 | 显示全部楼层
遇到这种问题,一旦搞不明白,我都直接强制转换永远不会错

出100入113汤圆

发表于 2019-2-19 13:54:04 | 显示全部楼层
j溢出  先赋值  再右移

出200入2554汤圆

发表于 2019-2-19 14:31:10 | 显示全部楼层
短类型直接移位,不出错都是运气。ICCAVR 还负责一点,给出了提示:



先强制类型转换,再进行移位才安全。以下内容是 VS 中 windef.h 的数据拼接宏:
  1. #define MAKEWORD(a, b)      ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8))
  2. #define MAKELONG(a, b)      ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16))
  3. #define LOWORD(l)           ((WORD)((DWORD_PTR)(l) & 0xffff))
  4. #define HIWORD(l)           ((WORD)((DWORD_PTR)(l) >> 16))
  5. #define LOBYTE(w)           ((BYTE)((DWORD_PTR)(w) & 0xff))
  6. #define HIBYTE(w)           ((BYTE)((DWORD_PTR)(w) >> 8))
复制代码


类型转换、括号顺序几乎写到了啰嗦的地步

本帖子中包含更多资源

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

x

出0入50汤圆

发表于 2019-2-19 14:42:26 | 显示全部楼层
k=j<<16;
你忽略了j中间运算中就溢出了,j的定义是uchar啊

出0入0汤圆

发表于 2019-2-19 15:06:58 | 显示全部楼层
如果没有自动整形提升的话,三种写法都是错误的,应为 j是8位变量不能移了

出0入12汤圆

 楼主| 发表于 2019-2-19 16:41:08 | 显示全部楼层
zhugean 发表于 2019-2-19 15:06
如果没有自动整形提升的话,三种写法都是错误的,应为 j是8位变量不能移了 ...

肯定是自动提升了的,因为最后一种是正确的

出0入12汤圆

 楼主| 发表于 2019-2-19 16:42:03 | 显示全部楼层
68336016 发表于 2019-2-19 11:58
j是8位的,移那么多位可以吗?

k=j<<8; 这句是正确执行了的

出0入12汤圆

 楼主| 发表于 2019-2-19 16:43:59 | 显示全部楼层

依你的看法,k=j<<8; 会等于0,但事实不是你想的那样

出0入12汤圆

 楼主| 发表于 2019-2-19 16:45:49 | 显示全部楼层
1a2b3c 发表于 2019-2-19 13:52
遇到这种问题,一旦搞不明白,我都直接强制转换永远不会错

我用了强制转换:k=((ulong)j)<<16;也不对

出0入12汤圆

 楼主| 发表于 2019-2-19 16:48:53 | 显示全部楼层
t3486784401 发表于 2019-2-19 14:31
短类型直接移位,不出错都是运气。ICCAVR 还负责一点,给出了提示:

你试过 k=j<<8;吗?   怎么不会出错?

出0入50汤圆

发表于 2019-2-19 16:54:56 | 显示全部楼层
kuanglf 发表于 2019-2-19 16:43
依你的看法,k=j

我没有说会溢出就是0,只是知道这样做是错误的做法,至于出错的结果,不是我需要考虑的,都是错了,有什么区别呢?

就像不遵守交规的人,不一定都是完全一样的死法,没必要去纠结怎么死的,只要自己遵守交规就可以了嘛。

就此打住,要不然就成抬杠了,一点意思都没有。

出0入93汤圆

发表于 2019-2-19 19:11:36 | 显示全部楼层

我来回答吧,有时候还是要较真一下,互相探讨为好,抬杠的确实没有必要。
C语言按规范的实际上只有int和double类型有运算操作,更长的肯定要扩展否则就算不出来了,比它们小的类型就只好类型提升了。单片机的因为受到资源制约往往都不标准,好多double和float是一样的都是编译器的实现了。
那么uchar移位就应该使用int移位,这才是标准的。请注意:uchar是无符号的,但是很显然它能够类型提升到int,因此不会隐式转换为uint。那么:您的 j << 16就溢出了,因为int装不下,变成0了。然后就是 j << 8的问题。您能看到的是,j是uchar型,类型提升为int,那么j << 8就是int型,请注意,这里是有符号的!0xAA 左移8位变成了 0xAA00这是没错的,但是这个是负数。然后你就在这里栽跟头了。请外面用(ulong)再进行强制转换,正规的应该是(ulong)(uint)(j << 8)。

BTW:就这么个拼接,用联合体或指针都要好得多

出0入0汤圆

发表于 2019-2-19 19:31:14 来自手机 | 显示全部楼层
这个看汇编比较直接

出0入0汤圆

发表于 2019-2-19 22:26:04 | 显示全部楼层
wye11083 发表于 2019-2-19 13:49
我是fpga软核。riscv目前还没有。你可以考虑stm32。arm,x86,riscv还是比较稳定的。mips有段时间编译器 ...


MIPS我玩过AR9331路由器当开发板,感觉还行。不下沉到汇编层面的话体会不到ARM和MIPS架构不同而对应用带来的区别。
至于丢CASE,也太奇葩了…


RISC-V据说前景很好,我还以为已经有应用出来了呢…


出0入442汤圆

发表于 2019-2-20 00:27:04 来自手机 | 显示全部楼层
fnems 发表于 2019-2-19 22:26
MIPS我玩过AR9331路由器当开发板,感觉还行。不下沉到汇编层面的话体会不到ARM和MIPS架构不同而对应用带 ...

有,国产好多小嵌入式芯片都是rv32imdc的方案。年前重庆有家公司来我们这推销低功耗三核rv32 ai处理器。我敢说,riscv将来会占据嵌入式半壁江山,然而它并不能撼动arm和x86。新的硬件集成商都会慢慢转向riscv,如西数都开源了自有soc。关键是riscv面积小,性能强,代码密度高,理念先进。

至于mips gcc丢case我也无语,x86不丢就mips丢。当时在板上死活跑不出来结果,我查汇编才查出来。后来我改成if else然后把顺序倒了半天才找回来(case在mips汇编下有值注释,可以数出来丢了)。

路由器处理器一般不算太强,ar9341可以,就是太老了,不支持1gbps。这也是老家伙的缺点吧。所以我前段时间把所有网络设备全部换成1gbps的了,9341正式淘汰。

出0入30汤圆

发表于 2019-2-20 10:54:29 | 显示全部楼层
takashiki 发表于 2019-2-19 19:11
我来回答吧,有时候还是要较真一下,互相探讨为好,抬杠的确实没有必要。
C语言按规范的实际上只有int和d ...

向各位牛人学习了,

出0入475汤圆

发表于 2019-2-20 12:03:30 | 显示全部楼层
kuanglf 发表于 2019-2-19 16:45
我用了强制转换:k=((ulong)j)

要是你按照我说的,肯定不会错,虽然我不懂C语言,都是简单自学的一点,所以我才会很笨的强制转换!
你第二种方法中,你只说了8-->32强制,那么你的8-->16强制了吗?没有,就是你那个k+=(j<<8);,,要你是按照我一样的不懂的C语言的方式去做,改成 k+=(((unsigned short)j)<<8);那么一切问题就解决了。。。

就像前面有网友说的,你说的那个直接移动是正确的,可能的确是有运气和巧合在里面啊

我上面的验证的是在keilC51下面验证的,直接copy你的代码运行,结果和你的一样,都是54AA33,但是你按照我说的试试呢,那么就是正确的答案55AA33了 祝好运

出0入475汤圆

发表于 2019-2-20 12:05:09 | 显示全部楼层
哦,原来23楼 takashiki 已经分析了,高

出200入2554汤圆

发表于 2019-2-20 13:33:48 | 显示全部楼层

编译器的提示中已经提到了 int 类型了,这也如 23 楼解释的一样,uchar 移位时自动升级到有符号的 int 了。

强制类型转换诶,这种时候还是不要省

出0入12汤圆

 楼主| 发表于 2019-2-20 17:58:27 | 显示全部楼层
takashiki 发表于 2019-2-19 19:11
我来回答吧,有时候还是要较真一下,互相探讨为好,抬杠的确实没有必要。
C语言按规范的实际上只有int和d ...

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

本版积分规则

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

GMT+8, 2024-4-26 11:24

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

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