C++位運算詳解


位簡介

位是數據存儲的最小單位。在 計算機中的二進制數系統中,位,簡記爲b,也稱爲比特,每個0或1就是一個位(bit)。

位操作詳解

我們先來看看位運算操作符:& (按位與)、| (按位或)、^ (按位異或)、~ (按位取反)、>> (按位右移)、<< (按位左移)。

1、&(按位與) 從概念上來講,就是將參與運算的兩個分量對應的每一位來做邏輯與運算,若兩者都爲真(等於1),則結果才爲真(等於1)。否則都爲假(等於0)。
即:1 & 1 = 1 、1&0 = 0 、0&1 = 1、0&0 = 0
這裏我們先來看看那一個8位二進制的例子:
7&8 = 0000 0111 & 0000 1000 = 0000 0000 = 0
7&6 = 0000 0111 & 0000 0110 = 0000 0110 = 6

2、| (按位或) 即把參與運算的每個分量對應的每一位來做邏輯或運算,即兩者都爲假(爲0)時,才爲假(爲0),否則皆爲真。
即:0|0 = 0、1|0 = 1、0|1 = 1、1|1 = 1
來看看8位二進制的例子:
7|8 = 0000 0111 | 0000 1000 = 0000 1111 = 15
7|6 = 0000 0111 | 0000 0110 = 0000 0111 = 7

3、^(按位異或) 即把參與運算的每個分量對應的每一位來做異或運算,即兩者相同爲假,不同爲真。
即:0|0 = 0、 1|0 = 1、0|1 = 1、 1|1 = 0
看下面的例子:
7^8 = 0000 0111 ^ 0000 1000 = 0000 0111 = 7
7^6 = 0000 0111 ^ 0000 0100 = 0000 0011 = 3

4、~(按位取反) 即把二進制位的每一位進行取反運算,簡而言之就是1變成0,0變成1。
直接看例子:
~7 = ~0000 0111 = 1111 1000 = 248

5 >>(按位右移)把二進制位整體向右移動。
7>>1 = 0000 0111 >> 1 = 0000 0011 = 3
7>>2 = 0000 0111 >> 2 = 0000 0001 = 1
這裏右移等於除了2的N次方,N爲右移的位數。

6 <<(按位左移)這裏就不詳細說了,和右移相反。

位操作應用

好了,下面講講實際應用吧。
一、一種顏色的表示方式—- 通過DWORD來表示顏色
定義:typedef unsigned long DWORD;
即爲一個無符號32位(32機器)長整數,有四個字節,我們從左到右叫他1,2,3,4字節,每一個字節的範圍是0~255。第一個字節表示alpha值,即透明度。如果是255,表示不透明,0表示完全透明(

看不到),其他分別是R,G,B值。
可通過下列方法獲得每個字節的值:
int A = (int)((DWORD & 0xFF000000) >> 24);
int R = (int)((DWORD & 0x00FF0000) >> 16);
int G = (int)((DWORD & 0x0000FF00) >> 8);
int B = (int)(DWORD & 0x000000FF);

DWORD dwColor = (A<<24)+(R<<16)+(G<<8)+B;
有了前面的基礎,我相信大家對上面的換算方法,一看就明白吧。如果對16進制不敏感的童鞋,可以用計算機把十六進制換算成二進制,更容易理解。

二、狀態系統中的使用

在遊戲開發中,我們通常用一個32位(假設這裏用32位)的整數來存儲角色的狀態(這樣做主要是爲了節約存儲空間,同時也減小網絡同步消息包的size)。所謂的狀態,就是大家熟悉的Buff或者DeBuff。
enum ROLE_STATUS
{
STATUS_NORMAL = 0, // 正常
STATUS_DIE = 1, // 死亡狀態
STATUS_GOD , // 無敵
STATUS_DISAPPEARING , // 消失中狀態
STATUS_DEF_ADJUST , // 物理防禦提升/降低
STATUS_MDEF_ADJUST , // 魔法防禦提升/降低
STATUS_ATK_CRI_ADJUST , // 同時提升物理攻擊和爆擊率
STATUS_MAXHP_ADJUST , // HP上限調整
STATUS_MAXMP_ADJUST , // MP上限提升/降低
//……
這裏最多隻能寫32個,因爲我們假設是用32位數據來存儲狀態。
};

狀態數據定義好了,現在來看看怎麼使用他們。
首先, 角色上線,我要給他一個保護狀態,應該這樣操作。
DWORD dwRoleStatus = STATUS_GOD;
同時,角色使用了一個物品,這個物品的效果時,HP和MP上限增加一段時間。因此要附加調整玩家的HP和MP上限的狀態,應該這樣。
DWORD dwRoleStatus |= (STATUS_MAXHP_ADJUST+STATUS_MAXMP_ADJUST);
這裏是|=而不是=操作,因爲不能清掉之前附加的無敵保護狀態。所以用或運算。
該角色受到其他玩家或者怪物的攻擊,我們要判斷被攻擊的這個角色的受保護狀態狀態還在不在。執行如下邏輯
if( dwRoleStatus & STATUS_GOD ) // 判斷位是否爲1
{
// 受保護狀態,不能被攻擊
}

接下來,角色無敵保護時間過期了,我們要清除無敵狀態,執行如下操作
dwRoleStatus &= ~STATUS_GOD;
這裏用到了取反的計算。~STATUS_GOD的結果是第二位爲0外,其他都爲1。然後和dwRoleStatus做按位與計算。
STATUS_GOD 等於 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010;
~STATUS_GOD 等於 1111 1111 1111 1111 1111 1111 1111 1111 1111 1101;
因此和dwRoleStatus相與之後,dwRoleStatus除了第二位以外的位,都保留下來了。第二位不管是什麼值,都會被設置爲0,這樣子就把STATUS_GOD這個狀態清除掉了。同理我們要清除多個狀態的時候,先把要清楚的狀態或運算到一起。再取反,然後和dwRoleStatus按位與。起到同時清除多個狀態。

然後講講異或,它有一個性質是,兩次異或,能還原回來
例如 a=7,b=6;
a = a^b^b
我們來看看那二進制的操作
a = 0111
b = 0110
c = a^b = 0001
a = c^b = 0111
寫到這裏,想到一道經典的C++筆試題,即不需要第3個變量,交換兩個變量的值。
a = a^b = 0001
b = b^a = 0111
a = a^b = 0110
暫時寫到這裏,想到有補充的,再完善。

發佈了3 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章