首先,我们先了解一下相关的概念,我们目前的PC机上面,普遍使用的是32位机,一个整型int为4个字节,一个char为1个字节,一个字节为8位,这里的位的概念就是今天的主角,在嵌入式领域及系统软件应用非常广泛。c/c++是很特殊的高级语言,可以直接操作位,甚至还有位域的概念,可以为一个字节中的位分别定义概念。使用位,有什么好处呢,我想应该是可以节约内存,性能较高,作为标志位时,意义非常清晰。在win32 API里面的标志位通常就是用这个来完成的,一个字节就可以用于表示32个标志了。用上|或者&操作,看起来,多么完美啊。如我们用于判断路径是否为文件夹:
WIN32_FIND_DATA fileinfo; // File Information Structure
HANDLE hFile; // File Handle
hFile = FindFirstFile(sDir,&fileinfo);
// if the file exists and it is a directory
if(fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Directory Exists close file
FindClose(hFile);
}else{
if(!CreateDirectory(sDir,NULL)){
AfxMessageBox("本地创建目录[" + sDir + "]失败。");
return FALSE;
}
}
c的位操作主要包括
操作 | 运算符 | 等式及结果 | 点评 |
或 | | | 0000 0000 | 0000 1001 = 0000 1001 | 对每一位而言,逢1则为1 |
并且 | & | 0010 1111 & 1000 0000 = 0000 0000 | 对每位计算,逢0则为0,全1才为1 |
取反 | ~ | ~1010 0111 = 01011000 | 这个最好理解,逢1为0,逢0为1 |
异或 | ^ | 0000 1001 ^ 1010 1010 = 1010 0111 | 两个操作位不同则为1,相同则为0 |
左移 | << | 0101 1000 << 2 = 0110 0000 | 将所有位向左边移动,并将左边的移动位抛弃,右边补0 |
右移 | >> | 01100000 >> 4 = 0000 0110 | 将所有位向右边移动,右边移动位抛弃,左边补0 |
针对这几个运算符,我们试验一把
C的位操作
下面,我们再来看看C++的位操作是怎样的。C++的位操作,当然是STL的bitset了。
以下表摘自CPPPrimer第二版4.12
操作 | 功能 | 用法 |
test(pos) | pos位是否为1? | a.test(4) |
any() | 任意位是否为1? | a.any() |
none() | 是否没有位为1? | a.none() |
count() | 值是1的位的个数 | a.count() |
size() | 位元素的个数 | a.size() |
[pos] | 访问pos位 | a[4] |
flip() | 翻转所有的位 | a.flip() |
set() | 将所有位置设为1 | a.set() |
set(pos) | 将pos位置设为1 | a.set(4) |
reset() | 将所有位置设为0 | a.reset() |
reset(pos) | 将pos位置设为0 | a.reset(4) |
针对上面的c程序,我们可以写出对应的c++版本,这里也不去写了,毕竟针对bitset的操作不用像C那样做麻烦的16进制的计算
总结:
bitset相对于原始C的位操作,相对直观,代码清晰,易于理解,不需要程序做机械性的2进制及16进制的换算。对于比较少接触位操作的
人们而言未尝不是一种福音,但是对于经常做位操作的嵌入式程序员来讲,估计会觉得还是直接用位操作符比较省事。也许这种差别跟Unix的
CLI(命令行模式)及WIN的GUI(窗口界面)一样,从初步来看鼠标比较易用,但对于熟练人员而言(比如程序员),往往用命令行更加的高效,且
便于批处理。扯远了。其实,从辨证的角度是不是可以两者结合使用呢?像win专注于客户端,而让unix专注于服务器呢?又一次扯远了!