下面讨论整数的移位问题,包括有符号整数和无符号整数的左移和右移,其他情况可作参考。
概念:
逻辑移位:
逻辑左移:向左移位时将左边移出的高位丢弃,将右边空出的低位补0
逻辑右移:向右移位时将右边移出的低位丢弃,将左边空出的高位补0
算数移位:
算数左移:向左移位时将左边移出的高位丢弃,将右边空出的低位补0
算数右移:向右移位时将右边移出的低位丢弃,将左边空出的高位补0,最高位上保留符号位
实例:
#include "stdio.h"
int main()
{
signed int positive_val = 10;
signed int negative_val = -10;
unsigned int unsigned_val = 10;
int positive_sleft = positive_val << 1;
int negative_sleft = negative_val << 1;
int unsigned_sleft = unsigned_val << 1;
int positive_sright = positive_val >> 1;
int negative_sright = negative_val >> 1;
int unsigned_sright = unsigned_val >> 1;
printf("positive_sleft = %d\n", positive_sleft);
printf("negative_sleft = %d\n", negative_sleft);
printf("unsigned_sleft = %d\n", unsigned_sleft);
printf("positive_sright = %d\n", positive_sright);
printf("negative_sright = %d\n", negative_sright);
printf("unsigned_sright = %d\n", unsigned_sright);
return 0;
}
输出为:
positive_sleft = 20
negative_sleft = -20
unsigned_sleft = 20
positive_sright = 5
negative_sright = -5
unsigned_sright = 5
请按任意键继续. . .
汇编指令中,
shl:逻辑左移,
shr:逻辑右移,
sal:算术左移,
sar:算术右移,
上述源码的汇编代码为
#include "stdio.h"
int main()
{
000813C0 push ebp
000813C1 mov ebp,esp
000813C3 sub esp,12Ch
000813C9 push ebx
000813CA push esi
000813CB push edi
000813CC lea edi,[ebp-12Ch]
000813D2 mov ecx,4Bh
000813D7 mov eax,0CCCCCCCCh
000813DC rep stos dword ptr es:[edi]
signed int positive_val = 10;
000813DE mov dword ptr [positive_val],0Ah
signed int negative_val = -10;
000813E5 mov dword ptr [negative_val],0FFFFFFF6h
unsigned int unsigned_val = 10;
000813EC mov dword ptr [unsigned_val],0Ah
int positive_sleft = positive_val << 1;
000813F3 mov eax,dword ptr [positive_val]
000813F6 shl eax,1
000813F8 mov dword ptr [positive_sleft],eax
int negative_sleft = negative_val << 1;
000813FB mov eax,dword ptr [negative_val]
000813FE shl eax,1
00081400 mov dword ptr [negative_sleft],eax
int unsigned_sleft = unsigned_val << 1;
00081403 mov eax,dword ptr [unsigned_val]
00081406 shl eax,1
00081408 mov dword ptr [unsigned_sleft],eax
int positive_sright = positive_val >> 1;
0008140B mov eax,dword ptr [positive_val]
0008140E sar eax,1
00081410 mov dword ptr [positive_sright],eax
int negative_sright = negative_val >> 1;
00081413 mov eax,dword ptr [negative_val]
00081416 sar eax,1
00081418 mov dword ptr [negative_sright],eax
int unsigned_sright = unsigned_val >> 1;
0008141B mov eax,dword ptr [unsigned_val]
0008141E shr eax,1
00081420 mov dword ptr [unsigned_sright],eax
printf("positive_sleft = %d\n", positive_sleft);
00081423 mov esi,esp
00081425 mov eax,dword ptr [positive_sleft]
00081428 push eax
00081429 push 85858h
0008142E call dword ptr ds:[89114h]
00081434 add esp,8
00081437 cmp esi,esp
00081439 call __RTC_CheckEsp (081136h)
printf("negative_sleft = %d\n", negative_sleft);
0008143E mov esi,esp
00081440 mov eax,dword ptr [negative_sleft]
00081443 push eax
00081444 push 85874h
00081449 call dword ptr ds:[89114h]
0008144F add esp,8
00081452 cmp esi,esp
00081454 call __RTC_CheckEsp (081136h)
printf("unsigned_sleft = %d\n", unsigned_sleft);
00081459 mov esi,esp
0008145B mov eax,dword ptr [unsigned_sleft]
0008145E push eax
0008145F push 85890h
00081464 call dword ptr ds:[89114h]
0008146A add esp,8
0008146D cmp esi,esp
0008146F call __RTC_CheckEsp (081136h)
printf("positive_sright = %d\n", positive_sright);
00081474 mov esi,esp
00081476 mov eax,dword ptr [positive_sright]
00081479 push eax
0008147A push 858ACh
0008147F call dword ptr ds:[89114h]
00081485 add esp,8
00081488 cmp esi,esp
0008148A call __RTC_CheckEsp (081136h)
printf("negative_sright = %d\n", negative_sright);
0008148F mov esi,esp
00081491 mov eax,dword ptr [negative_sright]
00081494 push eax
00081495 push 858C8h
0008149A call dword ptr ds:[89114h]
000814A0 add esp,8
000814A3 cmp esi,esp
000814A5 call __RTC_CheckEsp (081136h)
printf("unsigned_sright = %d\n", unsigned_sright);
000814AA mov esi,esp
000814AC mov eax,dword ptr [unsigned_sright]
000814AF push eax
000814B0 push 858E4h
000814B5 call dword ptr ds:[89114h]
000814BB add esp,8
000814BE cmp esi,esp
000814C0 call __RTC_CheckEsp (081136h)
return 0;
000814C5 xor eax,eax
}
000814C7 pop edi
000814C8 pop esi
000814C9 pop ebx
000814CA add esp,12Ch
000814D0 cmp ebp,esp
000814D2 call __RTC_CheckEsp (081136h)
000814D7 mov esp,ebp
000814D9 pop ebp
000814DA ret
结论:
左移:有符号整数和无符号整数的左移都是逻辑左移
右移:有符号整数的右移是算数右移,无符号整数的右移是逻辑右移
有符号整数:左移是逻辑移位,右移是算数移位
无符号整数:左移和右移都是逻辑移位
巧记:
左移:逻辑
右移:有符号:算数,无符号:逻辑