快速判断一个32位的字中是否存在值为"0"的byte
来源:互联网 发布:xen跟linux是什么关系 编辑:程序博客网 时间:2024/06/05 19:15
原文:http://blogread.cn/it/article.php?id=5908&f=sinat
首先为什么要做这样的判断呢?
当你要strcpy活着strcmp或者hash一个字符串的时候,传统的方法是每个byte进行比较。以strcpy为例,当一个字符串比较长,我们用32(或者64位)的字长进行copy的话,一次拷贝会拷贝4个byte,能节省很多时间(忽略内存对齐等情况)。
但是,使用32位的字长进行拷贝一个难点就是判断字符串的结尾,因为字符串长度不一定是4的整数倍,每次从内存中取4个byte,我们需要判断这4个byte中是否有某个byte是0,从而判断字符串是否结束。
最传统的做法就是对每个字节进行一次判断,或者将所有字节乘起来,看结果是否是0:http://www.spongeliu.com/
unsigned char * p = (unsigned char *) & v; bool hasNoZeroByte = *p && *(p + 1) && *(p + 2) && *(p + 3);
上面的代码需要12步操作,并且需要若干乘指令,效率不高。
一种传统有效的方法是通过对每个byte进行一次掩码的操作来判断是否存在0:
bool hasNoZeroByte = ((v & 0xff) && (v & 0xff00) && (v & 0xff0000) && (v & 0xff000000));
上面的操作相当于取出每一个byte,并进行与操作,最终判断是否是0,这样做需要进行7次操作。
那么,是否有更快的方法呢? 看下面的表达式:
unsigned int v; // 32-bit word to check if any 8-bit byte in it is 0bool hasZeroByte = ~((((v & 0x7F7F7F7F) + 0x7F7F7F7F) | v) | 0x7F7F7F7F);
这种方法进行了5次操作来完成整个工作!具体是怎么做到的,让我们仔细来看:
首先,将v同 0x7f7f7f7f 进行&操作,目的是将v中每个byte的最高位清零;
然后,再加上 0x7f7f7f7f 的目的是让每个byte的低7位溢出,这个时候只要每个byte的低7位不全是0,那么就会溢出;
随后,我们再将得到的数同原先的v进行一个“按位或”的操作,这样每个byte的最高位都会被置为1,除非这个byte初始为0(若初始为0,则第二步的时候不会溢出,第三步的时候0|0还是0);
再然后,我们再讲得到的数同 0x7f7f7f7f “按位或”,则如果初始的数不包含0byte,我们就会得到0xffffffff,否则我们得不到这个数;
最后,进行一个“按位否”操作,就会得到一个0或者非0。
我们用两个例子来更直观的说明,先举一个不包含0byte的32位数,以 0x5FF23D6E 为例:
0x5FF23D6E & 0x7F7F7F7F = 0x5f723d6e; //每个byte的高位全清00x5f723d6e + 0x7F7F7F7F = 0xdef1bced; //对每个byte的低7位进行溢出,只有当一个byte是0或者是“10000000”的时候不会溢出0xdef1bced | 0x5FF23D6E = 0xdff3bdef; //或上原来的数,这是除非一个byte初始是0,否则最高位都会是10xdff3bdef | 0x7F7F7F7F = 0xffffffff; //将所有bit置为1~ 0xffffffff = 0; //得到结果
再使用一个包含0byte的32位数为例,以 0x5FF2006E 为例:
0x5FF2006E & 0x7F7F7F7F = 0x5f72006e; //每个byte的高位全清00x5f72006e + 0x7F7F7F7F = 0xdef17fed; //对每个byte的低7位进行溢出,这个时候因为第三个byte是0,所以这个byte的最高位不是10xdef17fed | 0x5FF2006E = 0xdff37fef; //或上原来的数,第三个byte最高位不是10xdff37fef | 0x7F7F7F7F = 0xffff7fff; //第三个byte最高位不是1,其他所有位都是1~ 0xffff7fff = 0x8000; //得到结果
这种方法在一些字符串操作的性能优化,尤其是当大量字符串需要被哈希、拷贝时还是比较有效的。
参考资料:http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
- 快速判断一个32位的字中是否存在值为"0"的byte
- 判断一个字符串是否为已存在的文件夹
- SQL Server中判断一个数据库是否存在的方法
- SQL Server中判断一个数据库是否存在的方法
- C/C++中判断一个文件是否存在的方法
- SQL Server中判断一个数据库是否存在的方法
- C++中判断一个文件是否存在的方法
- Android的SQLite中如何判断一个表是否存在
- 在一个长度为n(n < 1000)的整数序列中,判断是否存在某两个元素之和为k。
- 取出Set中的byte数组的值以及判断byte数组是否为空
- 一个长度为N的整形数组,数组中每个元素的取值范围是[0,N-1],写一个算法判断数组中是否存在重复的数字
- C++ 如何判断一个int数据的某一位是否为0
- PHP中如何检测一个值为null的变量是否存在
- 判断连续的位区间是否全部为0
- PHP判断数组中是否存在相同的值
- PHP判断数组中是否存在相同的值
- [VB.NET]如何在一个窗体M中判断另一个窗体N中是否存在一个名称为A的事件?
- shell 中一个变量是否为数字的判断
- c#集合讲解
- 库克究竟与乔布斯差在哪里?
- xwindwos一些程序库
- Struts2的select使用
- SQLserver在命令行(CMD)中的使用方法
- 快速判断一个32位的字中是否存在值为"0"的byte
- 【Shell】shell中的if语句判断参数
- source insight 常用快捷键
- 配置ISCSI客户端(LINUX)
- 云测试
- 云故事
- 在VS2008开发环境下,如何配置Lib库和dll库的名称
- VC自绘滚动条
- C++文件操作详解