
正文目录: 1. 位相关的运算符2. 位相关的用法 3. 位字段 (bit field) 4. 怎样判断机器的字节顺序? 5. 怎样将整数转换到二进制或十六进制? 6. 怎样高效地统计整数中为1的位的个数? 7. 相关参考 写作目的:
测试环境:
1) 取反:~ ~(10011010) = (01100101)运算符 ~ 把 1 变为 0,把 0 变为 1。 2) 按位与:& (10010011) & (00111101) = (00010001)运算符 & 通过逐位比较两个运算对象,生成一个新值。对于每个位,只有两个运算对象中相应的位都为 1,结果才为 1。 3) 按位或:| (10010011) | (00111101) = (10111111)运算符 | 通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中有 >=1 的位为 1,结果就为 1。 4) 按位异或:^ (10010011) ^ (00111101) = (10101110)运算符 ^ 逐位比较两个运算对象。对于每个位,如果两个运算对象中有且只有 1 位 为 1, 结果为 1。 5) 左移:<< (10001010) << 2 = (00101000)运算符 << 将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末端位的值会被丢弃,用 0 填充空出的位置。 6) 右移:>> (10001010) >> 2 = (00100010) // 情况1(10001010) >> 2 = (11100010) // 情况2 运算符 >> 将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末端位的值丢。 对于无符号类型,用 0 填充空出的位置。 对于有符号类型,其结果取决于机器。空出的位置可能用 0 填充,也可能用符号位填充。 2. 位相关的用法 1) 什么是掩码? 所谓掩码指的是一些设置为开 (1) 或关 (0) 的位组合。 为什么叫掩码?看下面这个例子: #define MASK (1<<1)flags = flags & MASK; 上面这个例子中,只有 MASK 中 为1的位才可见,掩码中的 0 隐藏 (掩盖) 了 flags 中相应的位。 ![]() 2) 打开 (设置) 位 flags |= MASK; 3) 关闭 (清空) 位 flags &= ~MASK; 4) 切换位 flags ^= MASK; 5) 检查位 (flags & MASK) == MASK 注意,掩码至少要与其覆盖的值的宽度相同,要避免符号位带来的意外,最好在代码中使用 unsigned int 操作位和字节。 6) 提取位 移位运算符可用于从较大单元中提取一些位,例如提取 RBG 颜色值: #define BYTE_MASK 0xffunsigned long color = 0x123456; unsigned char blue, green, red; red = color & BYTE_MASK; green = (color >> 8) & BYTE_MASK; blue = (color >> 16) & BYTE_MASK; 3. 位字段 ( bit field ) 位字段通过一个结构声明来建立,该结构声明为每个字段提供标签,并确定该字段的宽度,在 Linux 驱动中,某些代码使用了位字段: struct ap_queue_status {unsigned int queue_empty : 1; ... unsigned int response_code : 8; unsigned int pad2 : 16; } aqs; 给字段赋值: aqs.queue_empty = 0;aqs.response_code = 0xff; 所赋的值不能超出字段可容纳的范围。 位字段占用的空间: struct {unsigned int autfd : 1; unsigned int bldfc : 1; unsigned int undln : 1; unsigned int itals : 1; } prnt; struct { unsigned int code1 : 2; unsigned int code2 : 2; unsigned int code3 : 6; unsigned int code4 : 8; #if TEST unsigned int code5 : 10; unsigned int code6 : 12; unsigned int code7 : 24; #endif } prcode; int main(void) { printf("%ld %ld\n", sizeof(prnt), sizeof(prcode)); } 测试结果: 4 4 // without TEST4 12 // with TEST 系统会自动判断出需要几个 byte 的空间来存储数据,在我的机器上测试,一个成员最起码占用 1 个 byte。 位字段的储存顺序: 4. 怎样判断机器的字节顺序? 演示 demo: int main(void){ int x = 1; if (*((char *)&x) == 1) printf("little - endian\n"); else printf("big - endian\n"); return 0; } 运行效果: $ gcc byte_order.c -o byte_order$ ./byte_order little - endian 代码解析:
5. 怎样将整数转换到二进制或十六进制? 演示 demo: 进行任意进制数转换的小函数: #define BUF_SIZE (33)char *baseconv(unsigned int num,int base) { static char retbuf[BUF_SIZE]; char *p; ... p = &retbuf[sizeof(retbuf)-1]; *p='\0'; do { *--p="0123456789abcdef"[num % base]; num /=base; } while(num !=0); return p; } 在 main() 中进行测试: int main(void){ int a = 20; printf("%s\n", baseconv(a, 2)); printf("%s\n", baseconv(a, 16)); return 0; } 运行效果: $ gcc int_conv.c -o int_conv$ ./int_conv 10100 14 代码解析:
6. 怎样高效地统计整数中为1的位的个数? 演示 demo: 统计整数中为1的位的个数的小函数: static int bitcounts[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};int bitcount(unsigned int u) { int n=0; for(; u!=0; u>>=4) n += bitcounts[u & 0x0f]; return n; } 在 main() 中进行测试: int main(void){ int i = 0; for (i=0; i<=0x0f; i++) printf("%d\n", bitcount(i)); return 0; } 运行效果: $ gcc bit_counts.c -o bit_counts$ ./bit_counts 0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4 代码解析:
|