C语言-移位,位域,和运算符优先级
1. 位移操作 << >>
C提供了一系列的移位运算,以向左或者向右移动位模式。
1.1 左移,右边补0
简单的例子:
1 << 7
//1左移7位 即:1-> 1000 0000
左移:右边补0
项目的例子:
#define FUN_NUM ((1 << 7) - 1) //FUN_NUM 为127
1 左移7位 0000 0001 左移 = 1000 0000
减1 = 0111 1111 127
故 FUN_NUM = 127
注意运算符优先级: - 高于 << >>
1.2 右移,分为逻辑右移和算术右移
逻辑右移,左边补0
(逻辑右移 不管是什么类型,空缺自动补0)
算术右移,左边补最高有效位的拷贝(应用于有符号位的运算)
(算数右移 若是无符号数,则空缺补0,若是负数,空缺补1)
规定:
对于无符号数据,右移必须是逻辑的
对于有符号数据,几乎所有编译器对其进行算术右移,程序员也是这样使用;
例子1:
8 >>2 // 8右移2位 即: 1000 -> 0010
语法: 需要移位的数字 << />> 移位的次数
例子2:
int iTest = 8;
unsigned int uiTest = -8;
printf("iTest=%x\n",iTest>>1);
printf("uiTest=%x\n",uiTest>>1);
结果:
iTest=4
uiTest=7ffffffc
说明:8 1000 右移1位 0100 4
-8 源码:0x10 00 00 08
反码:0xff ff ff f7
补码:0xff ff ff f8(1111 1000)
右移1位 0xff ff ff fc(1111 1100)
有符号数和无符号数详解
https://blog.csdn.net/lqy971966/article/details/106033332
1.3 项目中常用:
背景: 如求很多 NAME_LEN_X 是不是在 NAME_LEN 集合中
typedef enum tagNAME_LEN
{
NAME_LEN_1 = 1 ,
NAME_LEN_2 ,
NAME_LEN_3 ,
NAME_LEN_4 ,
NAME_LEN_5 ,
NAME_LEN_6 ,
NAME_LEN_7 ,
NAME_LEN_MAX
}NAME_LEN;
for(int i=NAME_LEN_1; i<NAME_LEN_MAX; i++)
{
……
newName = (int)1<<i;
/*
1左移i位 即变成
NAME_LEN_1 0000 0010 2
NAME_LEN_2 0000 0100 4
……
NAME_LEN_7 1000 0000 128
*/
……
}
define NAME_BIT(name) (((int)0x1)<<name)
tag = NAME_BIT(NAME_LEN_1) |
NAME_BIT(NAME_LEN_2) |
……
NAME_BIT(NAME_LEN_7) ;
//tag = 1111 1111
比较:
define TEST(newName,tag) (((((int)0x1)<<newName) & tag))
即: 求 newName 是不是在 tag 中
2. 位域操作 :
-
定义: 有些信息存储时,并不需要占用一个完整的字节,而只需要占几个或一个二进制
-
例子:存放开关变量,只有0或1 两种状态
-
操作:
struct bs { int iSwitch:2; //开关变量 iSwitch 只要两个字节存储 int b:2; int c:6; }
3. 运算符优先级
- 指针优先,单目运算符高于双目运算符
- 算数> 移位 >位运算 如:
1 << 3+2 && 7 等价于 (1 << (3+2)) && 7 - 逻辑运算符最后计算
- 位异或:同为0 异为1, 0^0 = 0
- & :位与操作 1&2 = 0
- && :逻辑与操作 1&&2=1