原文转自:http://www.crazycpp.com/?p=82

前言

以前收藏过一篇讲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
暂时写到这里,想到有补充的,再完善。
 
疯刀 2011.6.26

<转>C++位运算详解的更多相关文章

  1. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  2. C语言位运算详解[转]

    作者:911 说明:本文参考了http://www2.tsu.edu.cn/www/cjc/online/cyuyan/,算是对其的修正,在此将本文列为原创,实有抄袭之嫌疑.甚是惭愧! 位运算是指按二 ...

  3. C语言位运算详解

    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整形操作数,即只能用于带符号或无符号的char.short.int与long类型 ...

  4. C语言位运算详解(转载)

    转载自:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html 位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C ...

  5. C# 位运算详解

    运算符 描述 &(位与) 当两个二进制操作位都为1时,结果就为1 |(位或) 当两个二进制操作位有1个为1时,结果就为1 ^(位异或) 当两个二进制操作位只有1个为1时,结果为1 ~(位非) ...

  6. shell基本计算、逻辑运算、位运算详解

    转:http://blog.chinaunix.net/uid-8504518-id-3918531.html Shell 提供大量的基本运算操作,在脚本中非常有用.Shell 对您提供的算术表达式求 ...

  7. Opencv中Mat矩阵相乘——点乘、dot、mul运算详解

    Opencv中Mat矩阵相乘——点乘.dot.mul运算详解 2016年09月02日 00:00:36 -牧野- 阅读数:59593 标签: Opencv矩阵相乘点乘dotmul 更多 个人分类: O ...

  8. java中位运算和移位运算详解

    一.位运算 (1)按 位 与 & 如果两个相应的二进制形式的对应的位数都为1,则结果为1,记为同1为1,否则为0.首先我们看一下对正数的运算        分别看一下正数和负数的具体运算步骤 ...

  9. Java的位运算符详解实例——与(&)、非(~)、或(|)、异或(^)

    位运算符主要针对二进制,它包括了:“与”.“非”.“或”.“异或”.从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行逻辑运算.下面 ...

随机推荐

  1. HDU 2561 第二小整数(排序,水)

    第二小整数 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  2. [BZOJ 1305] 跳舞

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1305 Solution: 发现res是否可行具有单调性,二分答案 容易看出每次check ...

  3. HDU 2819 Swap(二分图匹配)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2819 [题目大意] 给出一个棋盘,由白格子和黑格子组成,可以交换棋盘的行列, 使得其主对角线为黑格 ...

  4. 【递推】【卡特兰数】CODEVS 3134 Circle

    新GET了一种卡特兰数的应用…… 在一个圆上,有2*K个不同的结点,我们以这些点为端点,连K条线段,使得每个结点都恰好用一次.在满足这些线段将圆分成最少部分的前提下,请计算有多少种连线的方法. 不会证 ...

  5. Access转Sqlite的最简单的方法(不需要DB Manager)

    在网上查了很多方法,大部分都是需要DB Manager,但是DB Manager这个牛逼保护机制做得好,没有免费的注册码可用.还好下面有另一个办法实现Access转Sqlite: 首先要下载SQLit ...

  6. 引用日志log4net.dll的web.config配置

    <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigu ...

  7. SQL Server 存储过程小结

    Transact-SQL中的存储过程,非常类似于Java语言中的方法,它可以重复调用.当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句.这样就可以提高存储过程的性能. Ø ...

  8. Node.js的集群功能以及在Express的配置

    Node.js在v0.6.0版本下内置了集群功能,作为cluster模块,用于nodejs的多核处理,也比较容易通过脚本实现一个负载均衡的集群. 脚本参考了其他人的材料,建立一个server.js(因 ...

  9. WebLogic Server 12.1.2后的字符型安装模式

    weblogic Server 12.1.1全部都可以用原来方式. WebLogic Server 12.1.2后已经取消了console安装模式,目前只有gui和静默安装模式.并且安装方式下也有很大 ...

  10. 在Linux中切换用户时变成-bash-4.3$

    增加普通用户 [root@git-node1 ~]#useradd nulige [root@git-node1 ~]#passwd nulige 输入两次密码 [root@git-node1 ~]# ...