1.左移指令和右稱指令的種類及做用:數組
左移指令做用:左移指令將操做數的bit位向左移動n位,空出來的位用0填充。函數
左移指令包含sal和shl,這兩條指令的做用是相同的,空出來的位用0填充。測試
其中左移sal的指令用法:ui
.section .text .global _start _start: movb $0b11111111, %al #8字節 salb $3, %al movw $0b11111111, %ax #16字節 salw $3, %ax movl $0b11111111, %eax #32字節 sall $3, %eax movq $0b11111111, %rax #64字節 salq $3, %rax
其中左移shl的指令用法:spa
.section .text .global _start _start: movb $0b11111111, %al #1個字節 shlb $3, %al movw $0b11111111, %ax #2個字節 shlw $3, %ax movl $0b11111111, %eax #4個字節 shll $3, %eax movq $0b11111111, %rax #8個字節 shlq $3, %rax
右移指令做用:右移指令將操做數的bit位向右移動n位,sar執行算術移位(填上符號位),而shr執行邏輯移位(填上0).移位操做的目的操做數能夠是一個寄存器或是一個存儲器位置。
指針
右移指令sar和shrcode
其中右移sar的指令用法,sar右移會用符號位填充,若是符號位是1,就填充1,若是是0就填充0。原型
.section .text .global _start _start: movb $0b01111111, %al #符號位是0 sarb $3, %al movb $0b11111111, %al #符號位是1 sarb $3, %al movw $0x7FFF, %ax sarw $3, %ax movw $0xFFFF, %ax sarw $3, %ax movl $0x7FFFFFFF, %eax sarl $3, %eax movl $0xFFFFFFFF, %eax sarl $3, %eax movq $0x7FFFFFFFFFFFFFFF, %rax sarq $3, %rax movq $0xFFFFFFFFFFFFFFFF, %rax sarq $3, %rax
其中右移sar的指令用法,shr始終填充0編譯器
.section .text .global _start _start: movb $0b01111111, %al #符號位是0 shrb $3, %al movb $0b11111111, %al #符號位是1 shrb $3, %al movw $0x7FFF, %ax shrw $3, %ax movw $0xFFFF, %ax shrw $3, %ax movl $0x7FFFFFFF, %eax shrl $3, %eax movl $0xFFFFFFFF, %eax shrl $3, %eax movq $0x7FFFFFFFFFFFFFFF, %rax shrq $3, %rax movq $0xFFFFFFFFFFFFFFFF, %rax shrq $3, %rax
2.C語言中的同類操做符:it
左移操做符是>> 用法value >> 1
右移操做符是<< 用法value << 1
注意:
在c標準裏說明無符號值執行的全部移位操做都是邏輯移位,但對於有符號值,究竟是採用邏輯移位仍是算術移位取決於編譯器。
3.練習:
練習題摘自《c和指針》第5章操做符和表達式
3.1.請編寫函數
unsigned int reverse_bits(unsigned int value);
這個函數的返回值是把value的二進制位模式從左到右變換一下後的值。例如,在32位機器上,25這個值包含了下列各個位:
00000000000000000000000000011001
10011000000000000000000000000000
彙編code:
.section .text .global reverse_bits .type reverse_bits, @function reverse_bits: xorl %eax, %eax movl $32, %ecx reverse_bits_start: cmpl $0, %ecx je reverse_bits_end shll $1, %eax movl %edi, %esi andl $1, %esi orl %esi, %eax shrl $1, %edi decl %ecx jmp reverse_bits_start reverse_bits_end: ret
c測試代碼
#include <stdio.h> #include <assert.h> extern int reverse_bits(unsigned int ui); int main() { unsigned u; u = reverse_bits(0x7fffffff); assert(u == 0xfffffffe); printf("u(%x)\n", u); u = reverse_bits(0x00ffffff); assert(u == 0xffffff00); printf("u(%x)\n", u); u = reverse_bits(0xffff00ff); assert(u == 0xff00ffff); printf("u(%x)\n", u); u = reverse_bits(0xffffff00); assert(u == 0x00ffffff); printf("u(%x)\n", u); u = reverse_bits(0xff00ffff); assert(u == 0xffff00ff); printf("u(%x)\n", u); return 0; }
3.2.編寫一組函數,實現位數組。函數的原型應該以下:
void set_bit(char bit_array[], unsigned bit_number); void clear_bit(char bit_array[], unsigned bit_number); void assign_bit(char bit_array[], unsigned bit_number, int value); int test_bit(char bit_array[], unsigned bit_number);
每一個函數的第1個參數是個字符數組,用於實際存儲全部的位。第2個參數用於標識須要訪問的位。函數的調用者必須確保這個值不要太大,以致於超出數組的邊界。
第1個函數把指定的位設置爲1。
第2個函數則把指定的位清零。
若是value的值爲0,第3函數把指定的位清0,不然設置爲1.
至於最後一個函數,若是參數中指定的位不是0,函數就返回真,不然就返回假。
彙編code:
.section .text .global set_bit .type set_bit, @function set_bit: movl %esi, %edx shrl $3, %edx movb (%rdi, %rdx, 1), %r8b movb $1, %r9b movb %sil, %cl andb $7, %cl shlb %cl, %r9b orb %r8b, %r9b movb %r9b, (%rdi, %rdx, 1) ret .global clear_bit .type clear_bit, @function clear_bit: movl %esi, %edx shrl $3, %edx movb (%rdi, %rdx, 1), %r8b movb $1, %r9b movb %sil, %cl andb $7, %cl shlb %cl, %r9b notb %r9b andb %r8b, %r9b movb %r9b, (%rdi, %rdx, 1) ret .global test_bit .type test_bit, @function test_bit: movl %esi, %edx shrl $3, %edx movb (%rdi, %rdx, 1), %r8b movb $1, %r9b movb %sil, %cl andb $7, %cl shlb %cl, %r9b andb %r8b, %r9b movl $0, %eax #返回假 cmpb $0, %r9b je test_bit_false movl $1, %eax #返回真 test_bit_false: ret .global assign_bit .type assign_bit, @function assign_bit: cmpl $0, %edx je call_clear_bit call set_bit jmp assign_bit_end call_clear_bit: call clear_bit assign_bit_end: ret
c測試代碼:
#include <stdio.h> #include <assert.h> extern void set_bit(char arr[], unsigned int bit_number); extern void clear_bit(char arr[], unsigned int bit_number); extern int test_bit(char arr[], unsigned int bit_number); extern void assign_bit(char arr[], unsigned int bit_number, int value); void test_one_bit() { printf("test one bit start...\n"); unsigned char c = 0; set_bit(&c, 1); assert(test_bit(&c, 1) == 1); clear_bit(&c, 1); assert(test_bit(&c, 1) == 0); assign_bit(&c, 1, 1); assert(test_bit(&c, 1) == 1); assert(c == 2); assign_bit(&c, 1, 0); assert(test_bit(&c, 1) == 0); assert(c == 0); } void test_byte() { printf("test one byte start...\n"); unsigned char c = 0; int i; for (i = 0; i < sizeof(c) * 8; i++) { set_bit(&c, i); } assert(c == 0xff); for (i = 0; i < sizeof(c) * 8; i++) { assert(test_bit(&c, i) == 1); } for (i = 0; i < sizeof(c) * 8; i++) { clear_bit(&c, i); } assert(c == 0); for (i = 0; i < sizeof(c) * 8; i++) { assign_bit(&c, i, 1); } assert(c == 0xff); for (i = 0; i < sizeof(c) * 8; i++) { assign_bit(&c, i, 0); } assert(c == 0); } void test_two_byte() { printf("test two byte start...\n"); unsigned short s = 0; int i; for (i = 0; i < sizeof(s) * 8; i++) { set_bit((char *)&s, i); } assert(s == 0xffff); for (i = 0; i < sizeof(s) * 8; i++) { assert(test_bit((char *)&s, i) == 1); } for (i = 0; i < sizeof(s) * 8; i++) { clear_bit((char *)&s, i); } assert(s == 0); for (i = 0; i < sizeof(s) * 8; i++) { assign_bit((char *)&s, i, 1); } assert(s == 0xffff); for (i = 0; i < sizeof(s) * 8; i++) { assign_bit((char *)&s, i, 0); } assert(s == 0); } int main() { test_one_bit(); test_byte(); test_two_byte(); //test_xxoo(); return 0; }