今天看到了ELF hash算法的实现,里面有个异或操作
#include <stdio.h>
unsigned int elfhash( char * str)
{
unsigned int hash = 0 ;
unsigned int x = 0 ;
while ( * str)
{
hash = (hash << 4 ) + ( * str ++ );
if ((x = hash & 0xF0000000L ) != 0 )
{
hash ^= (x >> 24 );
hash &= ~ x;
}
}
return (hash & 0x7FFFFFFF );
}
int main(int argc, char *argv[])
{
printf("%s::%p\n", argv[1], (void *)elfhash(argv[1]));
return 0;
}
当32位的数的最高4位不为零时,进行特殊处理,防止下一次循环时溢出:
1. 把hash变量的最高的4位与5-8位进行异或
2. 然后再把hash变量的最高4位清零
处理完毕后,返回时先进行与操作,把最高位清零。
如果定义的是无符号整型数据,可以不用这一步(hash的高4位已经清零,没必要再来一次与操作)。
整个运行过程就是这样,但是好像有些值的ELF hash算法的结果一样:
如fffffffffffffffffffffffffffffff 和ffffffffffffffffffffffff 最后生成key的结果保证一样,但是在实际中不太可能出现。
读完这个例子,顺使总结了异或操作的用途:
1. 翻转某些特定位,常用于硬件操作的特殊寄存器对某一位采取翻转操作的情形。
a ^= (1 << n) 对a的第n位进行翻转
有人说异或可以实现取返的操作,比如32位,~a 的值相当于a^0xFFFFFFFF,不过我感觉如果当天吃的比较多,可以用异或来取返,一般情况下~a看起来要更简单一些。
2. 实现两个值交换
如a=4, b=5
a ^=b; b^=a; a^=b;
操作之后,a=5, b= 4
这种操作可以保证数据不溢出。有人说了,用加法也可以使得两个数交换,那样可能会产生数据溢出。
3. 将某位数置零,异或本身
a^=a;
MIPS汇编大概有这几种解决方法。
li $t0 0 ;把立即数0放在$t0寄存器中
move $t0 $zero ;这是利用MIPS的$zero寄存器始终为0的简化操作
addu $t0 $zero $zero ;用加法也可以实现赋值操作
xor $t0 $t0 $t0 ;自己异或,结果为0
这一条语句在MIPS汇编中有多种实现,看来还是非常灵活的。
4. 快速判断两个值是否相等
return (a^b == 0)