|
正文目录: 1. 位相关的运算符) y! J) M- M. ]5 Z6 H2. 位相关的用法! w+ |9 D" v) k5 w 3. 位字段 (bit field); l/ M" \8 F, H0 @+ f7 N: O0 A 4. 怎样判断机器的字节顺序?: u+ w- @2 w. P+ I' e 5. 怎样将整数转换到二进制或十六进制?3 T2 ` k& c5 u( k% c5 t 6. 怎样高效地统计整数中为1的位的个数? 7. 相关参考 写作目的:
测试环境:
1) 取反:~ ~(10011010) = (01100101)8 X- H6 p: P( G" I- S运算符 ~ 把 1 变为 0,把 0 变为 1。 2) 按位与:& (10010011) & (00111101) = (00010001)# ], V( n! y. [' U运算符 & 通过逐位比较两个运算对象,生成一个新值。对于每个位,只有两个运算对象中相应的位都为 1,结果才为 1。 3) 按位或:| (10010011) | (00111101) = (10111111)+ P* N9 K' I- ]6 C7 H9 T/ u0 s; I运算符 | 通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中有 >=1 的位为 1,结果就为 1。 4) 按位异或:^ (10010011) ^ (00111101) = (10101110) E$ K2 H G' D5 E7 }- i运算符 ^ 逐位比较两个运算对象。对于每个位,如果两个运算对象中有且只有 1 位 为 1, 结果为 1。 5) 左移:<< (10001010) << 2 = (00101000)& E% ^8 L% R @0 y9 g- k# J运算符 << 将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末端位的值会被丢弃,用 0 填充空出的位置。 6) 右移:>> (10001010) >> 2 = (00100010) // 情况1(10001010) >> 2 = (11100010) // 情况2 运算符 >> 将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末端位的值丢。 对于无符号类型,用 0 填充空出的位置。 对于有符号类型,其结果取决于机器。空出的位置可能用 0 填充,也可能用符号位填充。 2. 位相关的用法 1) 什么是掩码? 所谓掩码指的是一些设置为开 (1) 或关 (0) 的位组合。 为什么叫掩码?看下面这个例子: #define MASK (1<<1)# u1 {, I" f/ h4 C- ?% Qflags = flags & MASK;2 k5 e+ L5 U' x7 X, S2 d 上面这个例子中,只有 MASK 中 为1的位才可见,掩码中的 0 隐藏 (掩盖) 了 flags 中相应的位。
2) 打开 (设置) 位 flags |= MASK;! [2 S% T2 C( Y2 g+ u" q/ ?3 s 3) 关闭 (清空) 位: D) R+ |4 D7 R2 d; p flags &= ~MASK; 4) 切换位 flags ^= MASK;, u6 \$ f6 N f1 s1 k% { 5) 检查位 (flags & MASK) == MASK* a9 h8 Q2 F& ~) Q* r1 R 注意,掩码至少要与其覆盖的值的宽度相同,要避免符号位带来的意外,最好在代码中使用 unsigned int 操作位和字节。 6) 提取位 移位运算符可用于从较大单元中提取一些位,例如提取 RBG 颜色值: #define BYTE_MASK 0xffunsigned long color = 0x123456;8 Q% D% C4 n. _- z8 k unsigned char blue, green, red;! v6 C) Z9 m* k' g* Z. ~' Z' I 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;! |+ `. J! g: |. u" U ...7 C) e6 F; s2 L- R unsigned int response_code : 8; unsigned int pad2 : 16; } aqs; 给字段赋值: aqs.queue_empty = 0;aqs.response_code = 0xff; 所赋的值不能超出字段可容纳的范围。 位字段占用的空间: struct {) }4 R- @& _0 v: Aunsigned int autfd : 1; unsigned int bldfc : 1;+ b, M5 w) o& Z, J% b8 ] unsigned int undln : 1; unsigned int itals : 1;1 {+ V- J4 r) B0 u. ?, k' O7 \7 G" P } prnt; * S* b; R5 G; v/ ^9 r& D2 O1 M struct {. q; z8 |$ R5 W: H# u unsigned int code1 : 2; unsigned int code2 : 2; unsigned int code3 : 6;0 K% B6 V5 ` @9 P unsigned int code4 : 8;9 L: Q0 }* Q' s5 S" _' O, V f+ c- D" U #if TEST unsigned int code5 : 10; unsigned int code6 : 12; unsigned int code7 : 24;6 y/ d8 Y6 G# k1 |1 M. M #endif } prcode;( m* i. T u3 _/ B: l8 L. ^ K' v+ D int main(void) { printf("%ld %ld\n", sizeof(prnt), sizeof(prcode));. I, X& Q/ x- j6 `8 R8 I }$ M7 h& K- N/ u4 q 测试结果: 4 4 // without TEST O1 \$ M8 V& J4 12 // with TEST 系统会自动判断出需要几个 byte 的空间来存储数据,在我的机器上测试,一个成员最起码占用 1 个 byte。 位字段的储存顺序: 4. 怎样判断机器的字节顺序? 演示 demo: int main(void){ int x = 1; 3 L2 D( T2 r j" _" Z' W/ L0 l if (*((char *)&x) == 1) printf("little - endian\n"); i. Q0 M2 Z+ W6 l else# v/ T8 b/ D$ b, t' e8 l% l printf("big - endian\n"); 9 e5 G$ ]. h T return 0;! y! L- S3 X* P } 运行效果: $ gcc byte_order.c -o byte_order$ ./byte_order little - endian 代码解析:
5. 怎样将整数转换到二进制或十六进制? 演示 demo: 进行任意进制数转换的小函数: #define BUF_SIZE (33)( u, a1 E4 T$ bchar *baseconv(unsigned int num,int base) { static char retbuf[BUF_SIZE]; char *p; ( v3 j) _- G9 |1 W; t ...4 T4 A7 ?- D' N7 t" }7 H x- @3 H5 o& ]. {7 C p = &retbuf[sizeof(retbuf)-1];4 L4 f; U9 Q8 A; w *p='\0'; do { *--p="0123456789abcdef"[num % base]; num /=base;4 l, D6 o7 I: n& S( P2 L; C- l/ @4 r# W } while(num !=0);, {/ Q1 \( n1 C$ w5 _3 R" V1 G : w! |: o3 \ o5 { return p; }; ~' P) D4 h1 S- A2 o 在 main() 中进行测试: int main(void)5 C" x; i% v3 Y+ {" z' \{2 y" A) U% v I) {, ], L int a = 20; printf("%s\n", baseconv(a, 2)); printf("%s\n", baseconv(a, 16));$ }8 N2 O8 }6 B, Z 2 h' y, o7 e5 @5 v return 0; } T- k7 P; m x w, V) C 运行效果: $ gcc int_conv.c -o int_conv% G8 _1 f' R: c6 i" {+ T% L$ ./int_conv 3 ~, K7 F6 g( X 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};. y8 p0 Z- ^2 u" i+ H9 a# |) }5 ^$ w6 ^* E& ` int bitcount(unsigned int u)% f% e4 |4 i2 j$ o { int n=0;( t5 H1 D- l/ k% M3 ~- ]# A' y . g! i, M+ O1 m( }: ]1 x9 c for(; u!=0; u>>=4) n += bitcounts[u & 0x0f]; return n;% w! p2 `/ X3 U4 A6 j: e5 B }7 J$ ^2 R* T. ^" h- D5 w8 d 在 main() 中进行测试: int main(void){ int i = 0;% }8 u- b: u5 j( D & ?0 _. U7 J8 d- g8 s( n: |; m5 a b for (i=0; i<=0x0f; i++): E: n) |8 u6 w" | printf("%d\n", bitcount(i)); return 0; } 运行效果: $ gcc bit_counts.c -o bit_counts$ ./bit_counts 0 1 1 2 18 }2 K' `' T* h9 R# x5 I) @ 2 2 31 |$ t% I4 A& _6 X1 x; A1 Z' s 1 23 q1 W* Q2 |/ s* a8 r) U7 j 2* _9 V$ f; g2 Q" w 3 2; |, g( E2 X2 m. C 3 3( t2 P, r& q2 S 4 代码解析:
|
微信公众号
手机版