目录
为什么要写这篇
一个契机就是我看到的一篇判断大小端的文章,后面再解释和我要写的关系。 蓝牙发送报文是按照一个字节一个字节进行发送,能表示的范围有限,但是不少含义的数据是超过这个数值的,比如角度值范围为0~360°,一个字节能达到的最大数值是255。那怎么办呢?肯定是两个字节或多个字节来表示一个数据。合并目前的我理解看来有三种方法,1. 按位与来实现合并 2.使用宏 3.基于union联合体关键字来实现合并。
按位与来实现合并
也是最常用的一种。举例来说:关于4字节数组合并成32位无符号整数
uint8_t _pBuf[4];
uint32_t return_value = (((uint32_t)_pBuf[3] << 24) | ((uint32_t)_pBuf[2] << 16) | ((uint32_t)_pBuf[1] << 8) | _pBuf[0]);
可能有些小伙伴并不是这样写的,觉得差不多。比如我,在看到这之前,我的写法是:
uint8_t _pBuf[4];
uint32_t return_value = (uint32_t)(_pBuf[3] << 24) | _pBuf[2] << 16) | _pBuf[1] << 8) | _pBuf[0]);
我不太确定后一种结果怎么样,但我确定前一种结果肯定对。
为什么呢?和运算符优先级有点儿关系,优先级越高越先运算。来自C陷阱与缺陷的截图
()是最高优先级,(type)表示强制类型转换,在次高优先级。运算的结果比如(_pBuf[3] << 24)会先将结果保存在一个临时位置(可能是个寄存器),最终会将这个临时运算值抛弃。第一种写法显式的说明要放在uint32_t类型的临时变量。然后四个uint32_t类型的临时变量相或,得到的结果肯定是uint32_t类型数据。而第二种写法,强制类型转换在括号外部,(_pBuf[3] << 24)因为_pBuf[3]是个uint8_t类型的值,左移24位,我知道原来的8位肯定变为0了,左移16位,左移8位同理,(_pBuf[3] << 24) | _pBuf[2] << 16) | _pBuf[1] << 8) | _pBuf[0])有没有可能保存在uint8_t类型里,结果是_pBuf[0]然后又被强制类型转换成uint32_t类型呢?我不清楚。
后来了解到这是属于C语言隐式类型转换规则,可以去网上搜一搜。有一条是:
(类型提升)在表达式中char和unsigned char、short 和 unsigned