1. 位运算
-
按位运算
No. 操作符 功能 1 &
按位与 2 |
按位或 3 ~
按位取反 4 ^
按位异或 -
运算规则
p q p & q p | q p ^ q 0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 -
示例
-
按位与
让某一位或某些位为0
。int n = 0xFFFF; n = n & 0x0010;
截取二进制数中的一段值。
int n = 0xFFab; n = n & 0x00FF;
-
按位或
让某一位或某些位为1
。int n = 0x0000; n = n | 0x0010;
拼接两个二进制数。
int a = 0xab00; int b = 0x0012; int c = a|b;
-
按位取法
得到全部为1
的数字~0
。int n = ~0;// 等同于0xFFFF
使数字的部分清零
x& ~7
。int n = 0xFFFF; n = n & ~7;
-
按位异或
两个相等数异或结果为0
。int n = 0x1234; n = n^n;
对同一个变量两次异或,变会原值。
int a = 0x1234; int b = 0x1357; a = a^b; a = a^b;
-
逻辑运算与按位运算
- 逻辑运算结果只有
0
和1
两种值,按位运算有多种值。- 逻辑运算相当于把所有的非零值都变成
1
,再按位运算。
2. 移位运算
No. | 操作符 | 功能 |
---|---|---|
1 | << |
左移 |
2 | >> |
右移 |
-
左移
i<<j
表示i
中所有位向左移动j
个位置,右边填入0
。
所有小于int
的类型,移位以int
大小执行,结果为int
。 -
右移
i>>j
表示i
中所有位向右移动j
个位置,
对于unsigned
类型,左边填入0
;对于signed
类型,左边填入符号位。
所有小于int
的类型,移位以int
大小执行,结果为int
。 -
位移运算与乘除运算
位移运算与乘除运算运算有如下对应关系:No. 位移运算 乘除运算 1 x<<1
x*2
2 x>>1
x/2
3 x<<n
x*pow(2,n)
4 x>>n
x/pow(2,n)
5 x<<=1
x*=2
6 x>>=1
x/=2
7 x<<=n
x*=pow(2,n)
8 x>>=n
x/=pow(2,n)
- 试一试
x<<-2;// 未定义行为
- 练习
- 位的设置
i |= 1<<j;
- 位的清除
i &= ~(1<<j);
- 位的测试
i & 1<<j
- 位的设置
- 实践
用位表示下面的结构体。
typedef struct{
bool student; // true:表示学生,false:表示非学生
bool sex; // true:表示男,false:表示女
bool pass; // true:表示合格,false:表示不合格
};
3. 位域
3.1 位域是什么?
位域是又称作位段,是把一个字节中的二进位划分为几个不同的区域。
3.2 位域有什么用?
节省空间,有些信息不需要占用一个完整的字节。
3.3 位域怎么用?
-
定义位域
定义位域与结构定义相仿。- 语法
为了保证位域的可以移植性,成员类型通常为struct 位域结构名{ 类型 位域名:位域长度; };
unsigned int
和int
,C99可以使用bool
。 - 示例
struct Byte{ unsigned int b1:1; unsigned int b2:1; unsigned int b3:1; unsigned int b4:1; unsigned int b5:1; unsigned int b6:1; unsigned int b7:1; unsigned int b8:1; };
- 语法
-
位域变量
定义和使用位域变量与结构体相同。每个域有一个域名,允许在程序中按域名进行操作。void printByte(struct Byte a){ printf("%d",a.b1); printf("%d",a.b2); printf("%d",a.b3); printf("%d",a.b4); printf("%d",a.b5); printf("%d",a.b6); printf("%d",a.b7); printf("%d\n",a.b8); } int main () { struct Byte a; printByte(a); struct Byte b = {1,0,1,0,1,0,1,0,}; printByte(b); return 0; }
试一试
struct Byte c = {1,2,3,4,5,6,7,8,}; printByte(c);
void scanfByte(struct Byte* a){ scanf("%d",&a.b1); scanf("%d",&a.b2); scanf("%d",&a.b3); scanf("%d",&a.b4); scanf("%d",&a.b5); scanf("%d",&a.b6); scanf("%d",&a.b7); scanf("%d",&a.b8); }
-
位域大小
printf("sizeof(Byte) = %ld\n",sizeof(Byte));
struct Byte{ unsigned char b1:1; unsigned char b2:1; unsigned char b3:1; unsigned char b4:1; unsigned char b5:1; unsigned char b6:1; unsigned char b7:1; unsigned char b8:1; };
位域的存储由编译器实现决定。编译器规定存储单元大小(8位、16位、32位)。 编译器会把位域逐个放入存储单元,位域之间没有间隙,直到存储单元放不下下一个位域,然后从下个存储单元继续存放。也有编译器跨存储单元存放。存放顺序也是编译器决定。
整个结构体的总大小为最宽基本类型成员大小的整数倍。
网友评论