C语言3个8位数据 组合成一个32位数据 细节的讨论
最近在将一个汇编代码转成C语言,发现一个问题
u8 ad1,ad2,ad3;
u32 data1;
data1= ((u32)ad3<<16)+((u32)ad2<<8)+ad1; // 可以得到正确结果
data1= (ad3<<16)+(ad2<<8)+ad1; // 错误的结果 没问题啊,移位导致溢出 ad1, ad2, ad3其中要有一个类型是32位的才行。 cheng-8yang 发表于 2020-9-27 12:19
ad1, ad2, ad3其中要有一个类型是32位的才行。
ad3要32位,ad2至少要提升到u16才行。他这个组合方案本来就是给自己埋坑,用个联合体啥问题都没还省ROM省RAM省执行时间 联合体最简单,连移位都省了.效率也高. union Data
{
u8 ad;
u32 data1;
} data;
这样对吗? 用C语言一定要勤用类型强制转换 如果没有自动整型提升的话, (ad3<<16),(ad2<<8)的结果都是0。所以就是应该使用上面那种写法 有些编辑器 ad1+ad2 直接就会溢出 一般我这么写
((u8*)&data1) = ad1;
((u8*)&data1) = ad2;
((u8*)&data1) = ad3;
((u8*)&data1) = 0; zhugean 发表于 2020-9-27 13:18
一般我这么写
((u8*)&data1) = ad1;
((u8*)&data1) = ad2;
Keil C51是大端模式,你的代码是小端模式,LZ一测试结果还是不对,哈哈 这个要看系统位数和编译器,绝大多数版本比较新的C/C++编译器在32位或者64位系统下,这段代码都不会有问题。根据C/C++现在的标准,在表达式中,char 和 short 类型的值,无论有符号还是无符号,都会自动转换成 int 或者 unsigned int(如果 short 的大小和 int 一样,unsigned short 的表示范围就大于 int,在这种情况下,unsigned short 被转换成 unsigned int)。因为它们被转换成表示范围更大的类型,故而把这种转换称为“升级(promotion)。
data1= (ad3<<16)+(ad2<<8)+ad1这样的语句,ad3,ad2,ad1都会自动转换成unsigned int。如果你的系统是8位或者16位的,这样可能会有问题,因为有的编译器可能会不进行升级,但比较新的编译器应该都能处理的很好。
另外就是union的情况,比较早时,不同的编译器对union的处理也不完全相同,里面也是有坑的。所以有段时间,在写可移植代码的时候,是不推荐用union的。另外通讯代码中使用union要对数据大小端和处理器大小端的情况进行分别定义,而使用位移代码则不需要。
takashiki 发表于 2020-9-27 13:23
Keil C51是大端模式,你的代码是小端模式,LZ一测试结果还是不对,哈哈
大端模式就改一下好了,这样比移位效率高些 MOV R7,#0X00
MOV R6,ad2
MOV A,ad2
RLCA
SUBB A,A
MOV R4,A
MOV R5,A
上面的数据是 ad2转换成32位数据的汇编代码,也就是ad2<<8 的过程
R4R5R6R7 32位数据,直接给了R6,R4R5应该是0,可以编译后RLC A ,SUBB A,A 结果就可能不是0了。 zhugean 发表于 2020-9-27 13:54
大端模式就改一下好了,这样比移位效率高些
移位效率不低,特别是移8位,16位,24位之类的,对于8位机,好点的编译器都会优化为寄存器间拷贝,用指针或union会读写内存,效率反而更低。对于32位机,普遍都带桶型移位器,移位也不是问题,所有操作都在寄存器搞定,没有内存访问。之前我有位同事就是用指针来搞的,效率奇低,换成移位,速度马上提高了几倍,CPU是C66核的DSP zhugean 发表于 2020-9-27 13:54
大端模式就改一下好了,这样比移位效率高些
对头,我也是这么做。做个宏定义。 用第1种方法,或者用共同体。
第1种方法效率也可以,并且方便移植,不存在大端小端问题。
第2种方法明显是错误的写法。
本帖最后由 miaoguoqiang 于 2020-9-28 21:50 编辑
```
#define BYTE2U32(a,b,c,d) (((unsigned int)(a)<<24)|(((unsigned int)(b)<<16)|(((unsigned int)(c)<<8)|(d)
```
页:
[1]