转:快速判断一个32位的字中是否存在值为"0"的byte

http://www.spongeliu.com/421.html

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

首先为什么要做这样的判断呢?

当你要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 0
bool 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的高位全清0
0x5f723d6e + 0x7F7F7F7F = 0xdef1bced; //对每个byte的低7位进行溢出,只有当一个byte是0或者是“10000000”的时候不会溢出
0xdef1bced | 0x5FF23D6E = 0xdff3bdef; //或上原来的数,这是除非一个byte初始是0,否则最高位都会是1
0xdff3bdef | 0x7F7F7F7F = 0xffffffff; //将所有bit置为1
~ 0xffffffff = 0; //得到结果

再使用一个包含0byte的32位数为例,以 0x5FF2006E 为例:

0x5FF2006E & 0x7F7F7F7F = 0x5f72006e;  //每个byte的高位全清0
0x5f72006e + 0x7F7F7F7F = 0xdef17fed; //对每个byte的低7位进行溢出,这个时候因为第三个byte是0,所以这个byte的最高位不是1
0xdef17fed | 0x5FF2006E = 0xdff37fef; //或上原来的数,第三个byte最高位不是1
0xdff37fef | 0x7F7F7F7F = 0xffff7fff; //第三个byte最高位不是1,其他所有位都是1
~ 0xffff7fff = 0x8000; //得到结果

这种方法在一些字符串操作的性能优化,尤其是当大量字符串需要被哈希、拷贝时还是比较有效的。

参考资料:http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord

注:可以使用算法进一步计算出值为“0”的byte有多少个。

原文地址:https://www.cnblogs.com/igfirstblog/p/10006707.html

时间: 2024-10-03 01:14:41

转:快速判断一个32位的字中是否存在值为"0"的byte的相关文章

vc判断是32位编译还是64位编译判断是debug编译还是release编译

来源:http://www.greensoftcode.net/   发布日期:2014-03-28      点击次数:471 发布者IP:119.119.236.22 1.判断是debug编译还是release编译.如果_DEBUG定义了表示是debug编译,否则是release编译. 2.判断是32位编译还是64位编译.在 Win32 配置下,_WIN32 有定义,_WIN64 没有定义.在 x64 配置下,两者都有定义.即在 VC 下,_WIN32 一定有定义.因此,WIN32/_WIN

在32位PE文件中的任意一个节中添加代码

// SectionOp.cpp : 定义控制台应用程序的入口点. // /************************************************ *程序说明:在32位PE文件中的任意一个节中添加代码 *          第一个参数为PE文件 第二个参数为第N个节 * * 时间: 20170718 * Win10 VS2010 测试通过  ver 0.01 **************************************************/ #inc

64位系统下,一个32位的程序究竟可以申请到多少内存,4GB还是更多

前言: cpu的位是指一次性可处理的数据量是多少,1字节=8位,32位处理器可以一次性处理4个字节的数据量,依次类推.32位操作系统针对的32位的CPU设计.64位操作系统针对的64位的CPU设计.操作系统只是硬件和应用软件中间的一个平台.我们的CPU从原来的8位,16位,到现在的32位和64位. 背景: 电脑的内存是8GB, 装的是32位的Win 7 32位版本,系统认出的内存是3.5GB, 应该说是4GB,因为还有0.5GB内存分配给了显存. 笔者十分痛苦,花重金购置的骇客神条单条8GB竟然

vuex中filter的使用 && 快速判断一个数是否在一个数组中

vue中filter的使用 computed: mapState({ items: state => state.items.filter(function (value, index, arr) { return index < 5 }) }), 如上所示,对于vuex,我们在使用mapState获取state时, 可以使用filter来过滤其中的元素,在filter的回调函数中接受三个参数,第一个是value,即每一个元素的值: 第二个是index, 即每一个元素所在的index, 第三个

一个32位进程可以占用最大内存

这里说的内存是逻辑上的,也就是虚拟的.并不是物理上的内存空间.实际实现逻辑内存的时候如果物理内存不足就用辅存(硬盘).有的人自然要问:既然可以用辅存虚拟,那么每个进程不是想要多大虚拟内存就有多大么?实际不是这样,32位机决定了内存寻址空间最大只能是2的32次方,即4G 如果程序实际需要的内存大于虚拟内存(尽管没有达到4G),windows就会在右下脚出现一个黄色三角形里面有个感叹号.提示虚拟内存不足,要你设置虚拟内存为更大的值.如果不设置,或如你所说硬盘都不足4G就会自动终止进程终止不了就死机了

如何快速判断一个文件是否为病毒

先说一下写这篇文章的背景和目的.现在吾爱的『原创发布区』和『精品软件区』人气很旺,发布的软件非常多.但也有一些小人,在发布的软件里插些小玩具,当灰客.论坛派专人检测也是很困难的,工作量太大,查不过来,因此很大程度上要靠用户自己识别,于是就有了这篇文章.需要说明一下的是,这篇文章主要是快速辨别正常文件与病毒,我自己也不是专业人员,方法是我自己总结出来的,很业余,不过我觉得还是有些用处的.如果你有更好的办法,欢迎跟帖提出.下面正文开始. 分析一个文件是否为病毒有多种方法,比如用OD这样的调试器,用H

python中如何不区分大小写的判断一个元素是否在一个列表中

python中判断某一个元素是否在一个列表中,可以使用关键字in 和 not in. 示例如下: 如果需要输出相应的信息,可以搭配使用if语句,这里不赘述. ------------------------------------------------------------------------------------------分割线------------------------------------------------------------------------------

iOS生成一个32位的UUID

- (NSString *)uuidString { CFUUIDRef uuid_ref = CFUUIDCreate(NULL); CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref); NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref]; CFRelease(uuid_ref); CFRelease(uui

Python3基础 in 列表名 判断一个元素是否在列表中

镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ 1 code 1 list1=[1,2] 2 print(1 in list1) 2 show 1 True ------------------------------------------博文的精髓,在技术部分,更在镇场一诗.Python是优秀的语言,值得努力学习.我是跟着小甲鱼视频教程学习