4.3 位运算
二进制数据的运算称为位运算,位运算操作符有:
“<<”:左移运算,最高位左移到CF中,最低位补零。
“>>”:右移运算,最高位不变,最低位右移到CF中。
“|”:位或运算,在两个数的相同位上,只要有一个为1,则结果为1。
“&”:位与运算,在两个数的相同位上,只有同时为1时,结果才为1。
“^”:异或运算,在两个数的相同位上,当两个值相同时为0,不同时为1。
“~”:取反运算,将操作数每一位上的1变0,0变1。
位运算在程序算法中被大量使用,如不可逆算法MD5,就是通过大量位运算来完成的。如何使一个数不可逆转呢?利用位运算就可以达到目的,如x&0结果为0,而根据结果,是不可以逆推x的值的。由于大多数位运算会导致数据信息的丢失(取反~和异或^可以反推),因此,在知道原算法的前提下,使用逆转算法是无法计算出原数据的。在算术运算中,编译器会将各种运算转换成位运算,因此掌握位运算对于学会算法识别是一件非常重要的事。在VC++6.0中,位运算符号又是如何转换成汇编代码的呢?请看代码清单4-18。
代码清单4-18 位运算—Debug版
//C++源码说明:位运算
int BitOperation(int argc){
//将变量argc左移3位
argc=argc<<3;
//将变量argc右移5位
argc=argc>>5;
//将变量argc与0xFFFF0000做位或运算
argc=argc|0xFFFF0000;
//将变量argc与0x0000FFFF做位与运算
argc=argc&0x0000FFFF;
//将变量argc与0x FFFF0000做异或运算
argc=argc^0xFFFF0000;
//对变量argc按位取反
argc=~argc;
//返回argc
return argc;
}
//C++源码与对应汇编代码讲解
//C++源码对比,左移运算3次
argc=argc<<3;
00401498 mov eax, dword ptr[ebp+8]
;左移运算对应汇编指令SHL
0040149B shl eax,3
0040149E mov dword ptr[ebp+8],eax
//C++源码对比,右移运算5
argc=argc>>5;
004014A1 mov ecx, dword ptr[ebp+8]
;右移运算对应汇编指令SAR
004014A4 sar ecx,5
004014A7 mov dword ptr[ebp+8],ecx
//C++源码对比,位或运算,变量argc低16位不变,高16位设置为1
argc=argc|0xFFFF0000;
004014AA mov edx, dword ptr[ebp+8]
;位或运算对应汇编指令OR
004014AD or edx,0FFFF0000h
004014B3 mov dword ptr[ebp+8],edx
//C++源码对比,将变量argc低16位清0,高位不变
argc=argc&0xFFFF0000;
004014B6 mov eax, dword ptr[ebp+8]
;位与运算对应汇编指令AND
004014B9 and eax,0FFFFh
004014BE mov dword ptr[ebp+8],eax
//C++源码对比,对变量argc做异或运算
argc=argc^0xFFFF0000;
004014C1 mov ecx, dword ptr[ebp+8]
;异或运算对应汇编指令XOR
004014C4 xor ecx,0FFFF0000h
004014CA mov dword ptr[ebp+8],ecx
//C++源码对比,将argc按位取反
argc=~argc;
004014CD mov edx, dword ptr[ebp+8]
;取反运算对应汇编指令NOT
004014D0 not edx
004014D2 mov dword ptr[ebp+8],edx
代码清单4-18演示了有符号数的移位运算,对于无符号数而言,转换的位移指令将会发生转变,如代码清单4-19所示。
代码清单4-19 无符号数位移—Debug版
//C++源码说明:无符号数位移
int BitOperation(int argc)
{
unsigned int nVar=argc;
nVar<<=3;
nVar>>=5;
}
//C++源码与对应汇编代码讲解
unsigned int nVar=argc;
004016C8 mov eax, dword ptr[ebp+8]
004016CB mov dword ptr[ebp-4],eax
//C++源码对比,对变量nVar左移3位
nVar<<=3;
004016CE mov ecx, dword ptr[ebp-4]
;和有符号数左移一样
004016D1 shl ecx,3
004016D4 mov dword ptr[ebp-4],ecx
//C++源码对比,对变量nVar右移5位
nVar>>=5;
004016D7 mov edx, dword ptr[ebp-4]
;使用shr进行右移位,最高位补0,最低位进CF
004016DA shr edx,5
004016DD mov dword ptr[ebp-4],edx
在代码清单4-19中,对于左移运算而言,无符号数和有符号数的移位操作是一样的,都不需要考虑到符号位。但右移运算则有变化,有符号数对应的指令为sar,可以保留符号位;无符号数不需要符号位,所以直接使用shr将最高位补0。