C语言笔记之二进制
1. 位运算
- 按位运算
No. | 操作符 | 功能 |
---|---|---|
1 | & |
按位与 |
2 | | |
按位或 |
3 | ~ |
按位取反 |
4 | ^ |
按位异或 |
- 运算规则
A | B | A & B |
A | B |
A ^ B |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
- 示例
(1)按位与
让某一位或某些位为0
。
int n = 0xFFFF;
n = n & 0x0010;
截取二进制数中的一段值。
int n = 0xFFab;
n = n & 0x00FF;
(2)按位或
让某一位或某些位为1
。
int n = 0x0000;
n = n | 0x0010;
拼接两个二进制数。
int a = 0xab00;
int b = 0x0012;
int c = a|b;
(3)按位取反
得到全部为1的数字~0
。
int n = ~0;// 等同于0xFFFF
使数字的部分清零x& ~7
。
int n = 0xFFFF;
n = n & ~7;
(4)按位异或
两个相等数异或结果为0
。
int n = 0x1234;
n = n^n;
对同一个变量两次异或,变会原值。
int a = 0x1234;
int b = 0x1357;
a = a^b;
a = a^b;
逻辑运算与按位运算
1.逻辑运算结果只有0
和1
两种值,按位运算有多种值。
2.逻辑运算相当于把所有的非零值都变成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) |
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;
}
- 位域大小
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位)。 编译器会把位域逐个放入存储单元,位域之间没有间隙,直到存储单元放不下下一个位域,然后从下个存储单元继续存放。也有编译器跨存储单元存放。存放顺序也是编译器决定。
整个结构体的总大小为最宽基本类型成员大小的整数倍。