1.左移指令和右称指令的种类及作用:
左移指令作用:左移指令将操作数的bit位向左移动n位,空出来的位用0填充。
左移指令包含sal和shl,这两条指令的作用是相同的,空出来的位用0填充。
其中左移sal的指令用法:
.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的指令用法:
.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和shr
其中右移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语言中的同类操作符:
左移操作符是>> 用法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
#include
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
#include
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
set_bit(&c, i);
}
assert(c == 0xff);
for (i = 0; i
assert(test_bit(&c, i) == 1);
}
for (i = 0; i
clear_bit(&c, i);
}
assert(c == 0);
for (i = 0; i
assign_bit(&c, i, 1);
}
assert(c == 0xff);
for (i = 0; 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
set_bit((char *)&s, i);
}
assert(s == 0xffff);
for (i = 0; i
assert(test_bit((char *)&s, i) == 1);
}
for (i = 0; i
clear_bit((char *)&s, i);
}
assert(s == 0);
for (i = 0; i
assign_bit((char *)&s, i, 1);
}
assert(s == 0xffff);
for (i = 0; i
assign_bit((char *)&s, i, 0);
}
assert(s == 0);
}
int main() {
test_one_bit();
test_byte();
test_two_byte();
//test_xxoo();
return 0;
}