C語言的位操作常見例子
我們每一種計算機語言最終都會通過編譯器轉換成機器語言來執行,所以在程式設計中,位操作是常見且高效的資料處理手段之一,下面列出一些基於C語言的場景例項,便於日常開發中學習和使用
例一,編寫函式 getbits(x,p,n) 從數值x的第p位開始返回n位數值
#include <stdio.h> int getbits(unsigned x, int p, int n); int main() { unsigned x = 0xF994; int p = 4; int n = 3; int z = getbits(x, p, n); printf("getbits(%u (%x), %d, %d) = %u (%X)\n", x, x, p, n, z, z); } // ff9411111111100.101.00# original number // >> p+1-n[2] 0011111111100.101.# shift desired bits to right // & ~(~0 << n) [7] 0000000000000.101.# clear all the other (left) bits int getbits(unsigned x, int p, int n) { return x >> (p - n + 1) & ~(~0 << n); }
例二,編寫一個函式setbits(x,p,n,y),該函式返回對x執行下列的操作的結果的值:將x中從左第p位開始的n個(二進位制)位設定為y中最右邊n位的值,x的其餘各位保持不變
#include <stdio.h> unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y); int intLen(unsigned x); int main() { unsigned x = 171; // 1010 1011 --- > 101[0 1]011 unsigned p = 3; unsigned n = 2; unsigned y = 38; // 0010 0110 printf("result : %u \n", setbits(x, p, n, y)); return 1; } int intLen(unsigned x) { int len = 0; for (; x; x >>= 1) { len++; } return len; } unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y) { int length_y = intLen(y); int length_x = intLen(x); if (length_x - p - n < 0) { printf("move over size by x"); return 0; } if (length_y < n) { printf("move over size by y"); return 0; } // int pos = p -n + 1; // unsigned cpy = y & ~ (~0 << n); // unsigned xx = (x >> pos) & (~0 << n); // return xx |= cpy; unsigned tail = length_x - (p + n); // x需要分離的子資料 unsigned sub = x & ~(~0 << tail); // y 中需要替換的n位資料 unsigned cpy = y & ~(~0 << n); // x向右移位,保留左邊 x >>= length_x - p; // x再向左移,這樣最右邊的n為可以為0 x <<= n; //這樣可以把y的拷貝值拷貝過去 x |= cpy; // x再向左推進, 把剛剛的分離的n為先補0先 x <<= tail; // x的分離再補充回數值 x |= sub; return x; }
例三,編寫一個函式invert(x,p,n), 該函式返回對x執行下列操作後的結果的值:將x中左起第p位開始的n個(二進位制)位求反(即,1變成0,0變成1),x的其餘各位保持不變
#include <stdio.h> unsigned invert(unsigned x, unsigned p, unsigned n); int intLen(unsigned x); int main() { unsigned x = 171; // 1010 1011 --- > 101[0 1]011 printf("result: %u\n", invert(x, 3, 2)); return 1; } int intLen(unsigned x) { int len = 0; for (; x; x >>= 1) { len++; } return len; } unsigned invert(unsigned x, unsigned p, unsigned n) { int length_x = intLen(x); if (length_x - p - n < 0) { printf("move over size by x"); return 0; } unsigned tail = length_x - (p + n); // x需要分離的子資料 unsigned sub = x & ~(~0 << tail); // 0001 01[0 1] x >>= tail; // x ^= 0011 // 0001 0110 x ^= ~(~0 << n); // 101[10]000 x <<= tail; // 101[10]011 x |= sub; return x; }
例四,編寫一個函式rightrot(x,n):該函式返回將x迴圈右移(即從最右端移出的為將從最左端移入)n (二進位制) 位後所得到的值
#include <stdio.h> int intLen(unsigned x); unsigned rightrot(unsigned x, int n); int main() { unsigned x = 171; // 1010 1011 int n = 5; // assert x = 01011 101 = 93 printf("result = %u\n", rightrot(x, n)); return 1; } int intLen(unsigned x) { int len = 0; for (; x; x >>= 1) { len++; } return len; } unsigned rightrot(unsigned x, int n) { int length_x = intLen(x); if (length_x) { n %= length_x; if (n) { // x需要分離的子資料 unsigned sub = x & ~(~0 << n); // x 向右移動n位 x >>= n; //計算左邊位置需要填報多少位 int mov = length_x - n; //通過上面分離的子串構造新的等長新串 unsigned subx = sub << mov; subx ^= x; return subx; } else { return x; } } return 0; }
例五,在求對二的補碼時,表示式 x&(x-1) 可以刪除x中最右邊值為1的一個二進位制位。用這一方法重寫bitcount函式,以加快其執行速度
#include <stdio.h> int bitcount(unsigned x); int main() { printf("%d's bit count: %d\n", 1023, bitcount(1023)); printf("%d's bit count: %d\n", 1024, bitcount(1024)); } int bitcount(unsigned x) { int len = 0; for (; x; x &= x - 1) { len++; } return len; }