#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; class BitArray2D { private: int mRow, mCol; unsigned char **A, *B; bool isValid(int row, int col) { return row > 0 && col > 0 && row <= mRow && col <= mCol; } public: BitArray2D(const int &row, const int &col) : mRow(row), mCol(col) { if(!isValid(row, col)) std::cerr << "parameter error." << std::endl; int i, j; int r = row; int c = (col%8 == 0) ? col/8 : col/8 + 1; A = new unsigned char *[r](); B = new unsigned char[r*c](); for(i=0,j=0; i < r; i++) { A[i] = &B[j]; j += c; } } ~BitArray2D() { delete B; delete []A; } bool bitGet(int row, int col) { if(!isValid(row, col)) return false; return A[row][col >> 1] & (1 << col); } void setOne(int row, int col) { if(!isValid(row, col)) return; A[row][col >> 1] |= (1 << col); } void setZero(int row, int col) { if(!isValid(row, col)) return; A[row][col >> 1] &= ~(1 << col); } }; int main() { BitArray2D ba(3,4); ba.setOne(1,2); int i,j; for(i = 0; i < 3; i++) { for(j = 0; j < 4; j++) { std::cout << ba.bitGet(i,j) << " "; } std::cout << std::endl; } std::cout << ba.bitGet(1,2) << std::endl; }
想尽各种办法实现[][]的重载都失败了。只好用()替代。使用起来也还行。
#include <stdio.h> #include <stdlib.h> #include <string.h> /* * 1. clear * 2. setOne/Zero * 3. get */ #define SHIFT 5 // 32 = 2^5 #define MASK 0x1f // 0001 1111 5bits [0,31] void bitSetOne(int *A, int idx) { int *pA = A; // idx>>5即idx/32 1 left shift [0,31] // p[0] = p[0] | 000001000 idx & MASK即截取idx有效的范围(0~2^5),实际上改成判断更合适,最后取或运算设置进去。相当于取模的运算 pA[idx >> 5] |= (1 << (idx & MASK)); // 1左移这么多位,设置进去。在内存中,实际上的存储顺序还是从每个int的低位到高位,只不过读取的过程中经过了计算,对外就像是连续的 } void bitSetZero(int *A, int idx) { int *pA = A; pA[idx >> 5] &= ~(1 << (idx & MASK)); } int bitGet(int *A, int idx) { int *pA = A; return pA[idx >> 5] & (1 << (idx & MASK)); } #include <stdlib.h> int main() { const int N = 100; // 100 bits int A[1+N/32]; // size = 4 32 bits memset(A, 0, sizeof(A)); bitSetOne(A, 1); bitSetOne(A, 3); printf("%d ", A[0]); if(bitGet(A, 0)) printf("1"); else printf("0"); if(bitGet(A, 1)) printf("1"); else printf("0"); if(bitGet(A, 2)) printf("1"); else printf("0"); if(bitGet(A, 3)) printf("1"); else printf("0"); puts(""); bitSetZero(A, 1); if(bitGet(A, 1)) printf("1"); else printf("0"); puts(""); }
注意
1 逻辑右移和算术右移 逻辑右移,移走的位填充为0;算术右移,移走的位填充与符号位有关,例如如果为负数,则移走的位填充为1。 2 unsigned int 和 int C语言的标准指出,无符号数执行的所有移位操作都是逻辑的,而对于有符号数,采用哪种方式取决于编译器。算术左移和逻辑左移是相同的,而算术右移和逻辑右移,取决于符号位。因此,一个程序如果使用了有符号数,是不可移植的。嵌入式的程序通常采用交叉编译开发,如果定义为有符号的,就无法保证右移操作能跨平台使用,这就是为什么用unsigned int,而不用int的主要原因。