c/c++位运算妙用

  在vc++编程中,会发现微软的很多API里面都用到了位运算,比如这个函数:

CreateWindowExA(
    __in DWORD dwExStyle,
    __in_opt LPCSTR lpClassName,
    __in_opt LPCSTR lpWindowName,
    __in DWORD dwStyle,
    __in int X,
    __in int Y,
    __in int nWidth,
    __in int nHeight,
    __in_opt HWND hWndParent,
    __in_opt HMENU hMenu,
    __in_opt HINSTANCE hInstance,
    __in_opt LPVOID lpParam);

这是windows API里面创建窗口的函数,第四个参数dwStyle,表示窗口风格,窗口风格当然会有很多种, 而且很多种之间也是可以组合的,那么到底怎么样用一个参数表示这么多中风格以及这些风格之间的组合呢?注意到了在写程序的时候这个参数经常是这样的:

WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU ,很明显这个参数能用或运算组合在一起,我们在VS中右击转到定义, 发现WS_CAPTION这些宏其实都是一个16进制的数字, 是如WS_CATION, 跟踪发现WS_CAPTION其实是WS_BORDER和WS_DLGFRAME或运算结果,WS_BORDER = 0x00800000L,WS_BORDER,dwStyle这个参数归根接地都是由WS_BORDER这样最基本的风格位运算组合的。

  windows中DWORD为32位,我们仔细研究发现, 每种最基本的窗口风格如WS_BORDERz换换成二进制为100000000000000000000000,发现其32位中只有一位为1, 对应其他风格也都类似只有一位为1。假如窗口风格有32种(当然没那么多),那么dwStyle参数32位的每一位对应一种风格, 这一位为1就有这个风格, 为0 就没这个风格,这样我们就能通过位运算将不同的风格组合在一起或者去掉某种风格。在创建窗口的时候只需要解析出dwStyle对应的每一位是否为1我们就能知道是否要包含这种风格。说了这么多来看看我的代码吧:

//判断DWORD对应位是否为1
//b为需要判断的数, i为对应的位数
BOOL TestDword(DWORD b, DWORD i)
{
    ATLASSERT(i <= 31); 
    return (b&(0x01<<i))==0?FALSE:TRUE;
}


//将某一位置为1或者0
//p为需要改变的数的指针,i为需要置0的位数
//state为0或者1,
//其也只能为0或1(二进制每一位不是0就是1) void SetDWBit(DWORD* p, int i, DWORD state) { ATLASSERT(i <= 31 && (state == 0 || state == 1)); if (state == 0) *p &= ~(0x01<<i); else *p |= 0x01<<i; }

上文中我的代码因为是在ATL下写的所以用的ATLASSERT,大家没有使用ATL的可以自己改掉。注意到函数中我都是用0x01移位操作的。TestDword判断某一位是否为1, SetDwBit将对应的某一位置为0 或者1。有了这两个函数我们就能很方便的在自己的代码中使用位运算。比如我们可以用一个DWORD(32位)型变量表示某个对象对应的是否有32个状态,注意此处我的第二个参数是位数是对应0到31的所以需要0x01<<i这个操作, 当让我们也可以像windows一样定义出每种风格 0x00000001(0x01<<0),0x00000010(0x01<<1),0x00000100(0x01<<2)...,上面函数只需要稍改下就好。

  很多时候我们都可以用一个变量表示很多种状态,而不需要为每种状态定义一个变量,这样我们的程序会更简洁更高效。以上函数用到位运算,如果不熟悉位运算的可以自己查资料。有什么错误请大家指出。

posted @ 2014-06-27 10:35  菊花也是花  阅读(2209)  评论(0编辑  收藏  举报