算数移位与逻辑移位
[color=rgba(0, 0, 0, 0.9)] 在进行嵌入式开发中移位操作算是大家用得比较频繁的一个操作符,因为大部分外设寄存器的每个位一般都代表着一项功能的使能或者选择,这样我们需要对一个或者多个置位或者清零等就会考虑使用移位操作,如下定义的宏大家应该不陌生。
[color=rgba(0, 0, 0, 0.9)]
2# define SET_BIT(x,n) (x|(1<<(n-1)))
3# define CLEAR_BIT(x,n) (x&~(1<<(n-1)))
[color=rgba(0, 0, 0, 0.9)] 那么大家在使用这两个宏的时候可能对于x变量的属性并没有太多的关注,因为大部分的外设寄存器都是用的无符号整形来表示的,如果是有符号整形呢?或者是浮点呢?最后的结果是这样的呢? 1逻辑移位[color=rgba(0, 0, 0, 0.9)] 逻辑移位运算简单的说就是不考虑符号位的移位处理,左移低位补0,右移高位补0,仅仅只是一种逻辑上的移动,所以对于无符号类型一般属于逻辑移位。
[color=rgba(0, 0, 0, 0.9)]
[color=rgba(0, 0, 0, 0.9)]
2算术移位[color=rgba(0, 0, 0, 0.9)] 算数移位运算与逻辑移位的区别是其会考虑算数数值问题,所以会考虑符号位的处理,一般算数移位仅仅只针对有符号整形,其左移采用逻辑移位高位移出,低位补零,而右移则是高位用符号位填充,低位移除。
[color=rgba(0, 0, 0, 0.9)]
[color=rgba(0, 0, 0, 0.9)]
[color=rgba(0, 0, 0, 0.9)] 看到这里一些小伙伴该疑惑了,为什么逻辑左移和算数左移是一样的呢 ? 难道不是算数左移也保留符号位吗?又或者说有符号数到底使用的是逻辑左移还是逻辑右移?下面我将为大家一一解答。
参考Demo:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 char sVal1 = 64;
5 char sVal2 = -7;
6
7 /********************************
8 * Fuciton: 测量移位
9 * Author : (公众号:最后一个bug)
10 *******************************/
11int main(int argc, char *argv[]) {
12
13 printf("sVal1 = %d\n",sVal1);
14 sVal1 = sVal1<<1;
15 printf("sVal1<<1 = %d\n",sVal1);
16
17 printf("sVal2 = %d\n",sVal2);
18 sVal2 = sVal2<<1;
19 printf("sVal2<<1 = %d\n",sVal2);
20
21 sVal2 = sVal2<<4;
22 printf("sVal2<<4 = %d\n",sVal2);
23
25 return 0;
26}
运行结果如下图:
图片
分析一下:
从上面的结果可以看出,左移运算并不是与*2等价的,其存在溢出问题,由于符号位会被低位代替,所以其最终的符号由所移动的最后一位决定,大家在使用的时候需要注意。
5、浮点运算的移位问题
我们对浮点数一般都不进行移位操作,并且大部分编译都是禁止该类语法操作,因为浮点存储格式中具体的bit段是有具体含义的,并且控制在固定的bit上(可以参考:【典藏】别怪"浮点数"太坑(C语言版本)),比如你把阶码移动到了尾码,那么这个移位操作的结果代表什么意义?根本无法理解,不过有些小伙伴为了能够获得更高的效率,想直接通过移位来代替*2运算,会考虑直接操作阶码来进行处理,可以参考如下代码:
硬核代码:
1#include <stdio.h>
2#include <stdlib.h>
3
4float fVal = 3.123;
5double dVal = 3.123;
6
7//单精度浮点移位
8#define FLOAT_SFT(f ,n ) ({ \
9 int itemp = *(int*)&f;\
10 itemp += n * 0x00800000u; \
11 *(float*)&itemp;})
12
13//双精度浮点移位
14#define DOUBLE_SFT(d ,n ) ({ \
15 long long lltemp = *(long long*)&d;\
16 lltemp += n * 0x0010000000000000LL;\
17 *(double*)&lltemp;})
18
19/********************************
20 * Fuciton: 测量移位
21 * Author : (公众号:最后一个bug)
22 *******************************/
23int main(int argc, char *argv[]) {
24
25 printf("FLOAT_SFT(fVal ,1) = %f\n",FLOAT_SFT(fVal ,1));
26 printf("FLOAT_SFT(fVal ,-1) = %f\n",FLOAT_SFT(fVal ,-1));
27
28 printf("DOUBLE_SFT(dVal ,1) = %4.6f\n",DOUBLE_SFT(dVal ,1));
29 printf("DOUBLE_SFT(dVal ,-1) = %4.6f\n",DOUBLE_SFT(dVal ,-1));
30
32 return 0;
33}
简单分析一下:
上面的代码应该还是非常有意思的,可以真正体会到浮点数据的存储机构并且区分float类型和double类型的存储区别;
同时使用指针对数据进行转化也得到了非常好的应用,特别是大家在以后通信等字节传输过程中需要使用到拆字节传输,也能够在这个实例中受益。
|
|