ELFhash的个人理解
来源:互联网 发布:淘宝售后在哪评价呢 编辑:程序博客网 时间:2024/05/01 02:59
先上代码,ELF哈希函数(个人看来超简单的了,相比MD5哈希函数来说)。输入字符串,输出字符串的哈希值。
int ELFhash(char* key){
unsigned long h=0;
while(*key)
{
h = (h << 4) + *key++;
//printf("1: h =0x%x\n",h);
unsigned long g = h & 0xF0000000L;
//printf("2: g =0x%x\n",g);
if(g)
{
h ^= g >> 24;
//printf("h^=g>>24 3: h =0x%x\n",h);
}
h &= ~g;
//printf("h&=~g 4: h =0x%x\n",h);
}
printf(" ELFhash(key)= 0x%x\n",h%MOD);
//cout<<endl;
return h & 0x7fffffff;
}
初次拿到这个函数的时候,我几乎把h,g的一举一动都打印出来观察了,还是没看出个所以然来。
根据上网查到内容看,这个g是用来防止溢出的。
然后,我开始尝试弱化这个函数,把g去掉,咱就不管它溢出不溢出了,然后函数就变成了这个样子。
int ELFhash(char* key)
{
unsigned long h=0;
while(*key)
{
h = (h << 4) + *key++;
}
return h & 0x7fffffff;
}
瞬间就简单了不是么。几乎一眼就能看出来错位叠加了。
现在我们假设输入的字符串是“hello”,来模拟一下函数的执行内容。
字符串结尾是'\0',它就while循环的结束条件。
进入while循环后,执行的是
h = (h << 4) + key[0];
h = (h << 4) + key[1];
h = (h << 4) + key[2];
h = (h << 4) + key[3];
h = (h << 4) + key[4];
再直观一点,
h = (h << 4) + 0x68; // 'h'的ASCII值 十进制104 十六进制68
h = (h << 4) + 0x65;
h = (h << 4) + 0x6c;
h = (h << 4) + 0x6c;
h = (h << 4) + 0x6f;
再直观一点,
0x0000006f
0x000006c0
0x00006c00
0x00065000
+ 0x00680000
____________现在知道ELF哈希函数的基本原理了吧,因为是错位叠加,字符串中任何一个字符的改变都会令最后得到的哈希值不一样。
通过对比字符串的哈希值,可以知道字符串是否被篡改,从而达到字符串校验的目的。
好了,现在我们回到开头的地方,溢出是怎么回事?
因为原理是左移,错位叠加,当字符串比较长的时候,左移会导致最前面的,最高位的数据丢失。
int型整数不过是32位而已。不考虑溢出,撑死了只能校验长度为31的字符串。
那ELFhash是怎么解决溢出的问题呢?我们把g有关的代码截取出来,看看它做了什么。
g = h & 0xF0000000L;
h ^= g >> 24;
h &= ~g;
第一步,g = h & 0xF0000000,将h的0~27位置零,28~31位不变,赋给g。
我们来模拟一下即将溢出的情况,31个字符的ASCII值错误叠加之后,此时最高的1位(16进制的最高的1位,对二进制来说就是最高的4位)不为1。
如果此时不做任何处理,下一轮第32个字符进来,左移,最高1位就溢出了。
怎么处理呢?
先把h的最高的1位(16进制的最高一位)取出来,判断它是否为0,如果0,说明左移之后没有溢出风险,否则,有溢出风险。
取一个数的某几位通常做法就是按位与。
第二步,h ^= g >> 24。
结合第一步,说白了,就是取h的最高1位(16进制的最高一位),挪到最低1位(16进制的最低一位),再与h本身异或。
我们知道,左移叠加的目的就是为了让每一个字符都对最终的哈希值产生影响。溢出会让最开始的字符失去影响力,最终哈希值只会被倒数共31个字符影响。
那么处理溢出最简单的方式,就是在溢出之前,把即将溢出的高位的影响力转移到低位去。这样一来,无论字符串多长,最后的哈希值会被所有字符影响。
第三步,h &= ~g。
g的最高1位跟h的最高一位相等,g的其余位为0。
结果就是h最高的1位(16进制)全部清0,其余位不变。第二步已经对最高8位的溢出做了处理,把影响力转移了,所以此时清零也无所谓了。
所以,整理下来,ELF哈希做了什么?
一个字符串进去,把每一个字符的ASCII码值错误叠加,最后得到一个整数。可以理解为得到了字符串的“密匙”,但是这个密匙只能甄别字符串是否被篡改,而不能翻译回原来的字符串。
等等......好像忘了点什么
对,return hash & 0x7fff fff, 最后哈希值还要最高一位(这次是二进制的最高一位)置0。
为什么?因为需要保证出来的哈希值赋过去之后是正整数。如果最高1位(2进制的)是1,而被赋值的数据是有符号的,就会变成负数。
好了全部讲完了,说真的,涉及到位运算的,解释起来都很费劲。位运算很高级,但是不好理解。
真的,如果谁丢了过来一段位运算的代码,还不带任何注释,我会想打人的~~
- ELFhash的个人理解
- ELFHash的理解
- 哈希表的ELFhash算法
- 著名的ELFhash算法
- ELFhash
- ELFhash
- ELFhash - 优秀的字符串哈希算法
- FormLayout的个人理解
- 数据仓库的个人理解
- SOA的个人理解
- cin的个人理解
- MVC的个人理解
- 狭义相对论的个人理解
- HashMap个人的理解
- HashSet的个人理解
- Vector的个人理解
- runtime的个人理解
- MVC的个人理解
- mysql管理性能状态查看命令
- 免费领取阿里云的优惠券
- HDU
- use local gradle distribution
- send函数阻塞
- ELFhash的个人理解
- 利用IntelliJ IDEA 搭建SSH整合
- iOS之动态计算UITableViewCell高度技巧(二)
- 异或运算
- 接口
- 一个MySQL 5.7 分区表性能下降的案例分析
- 函数分布
- Immutable 入门
- BUG_ON()和WARN_ON()的用法