练习和训练场
2013-12-10
ALIGN_TO(x,y)用法
今天看代码看到这个宏
#define ALIGN_TO(addr,level) \
(((addr)+((level)-1))&~((level)-1))
写了如下程序验证其用法:
#include<stdio.h>
#define ALIGN_TO(addr,level) \
(((addr)+((level)-1))&~((level)-1))
int main(int argc,char *agrv[])
{
int in_addr;
int in_level;
printf("Pls input two int number indicate addr and level:");
scanf("%d%d",&in_addr,&in_level);
printf("ALIGN_TO(%d,%d)=%d\n",in_addr,in_level,ALIGN_TO(in_addr,in_level));
return 0;
}
运行结果如下:
Pls input two int number indicate addr and level:854 16
ALIGN_TO(854,16)=864
Pls input two int number indicate addr and level:480 16
ALIGN_TO(480,16)=480
从结果中分析,可以看到这个宏实现了这样一种用途:
if(addr%level == 0)
result = addr;
else
result = (addr/level + 1)*level;
ASSERT(result%level); //这个用来测试result是否是level的整数倍
这里有个限制,level必须是2的指数幂,最大为2\^31 (gcc编译器),因为C语言中将整数扩展成signed int,32位的操作系统上int长度为32(gcc编译器)。
但是宏用了位运算,更简洁,效率更高,现在来分析这个过程: 相当于首先求level的二进制有n个0,然后将addr的低n位置为0,第(n+1)位加1。 我们知道右移1位相当于除以2,右移n位相当于除以 2\^n (=level)。
位操作妙用
1. 交换两个数
方法1:
a = a + b;
b = a - b;
a = a - b;
方法2:
if ( a! = b )
{
a = a\^b ;
b = a\^b ;
a = a\^b ;
}
2. 取模运算
int a, b, c ;
c = a % b ;
当b是2的幂时,可以转化为位与运算:c = a & ( b - 1 )
3. 将加法运算转换为位操作
思路是
- a.两个数相加,转化为2进制后各位相加无非是 0+0=0,1+1=0,1+0=1,0+1=1. 这个明显是异或操作。
- b.只有 1+1 会产生进位,于是可以看做是 这两个数做位与运算,然后左移。
- 将上面的两个数相加。(递归a,b,直到b中产生的数为0)
c代码如下:
#include<stdio.h>
int add_without_arithmetic(int num1, int num2)
{
if(num2 == 0)
return num1;
int sum = num1 ^ num2;
int carry = (num1 & num2) << 1;
return add_without_arithmetic(sum, carry);
}
/*
* Function : To flush stdin when input unmatched number
* /
void flush()
{
char c;
while((c=getchar()) != '\n' && c != EOF);
}
int main(int argc,char *argv[])
{
int a,b;
printf("pls input a b:");
while( scanf("%d %d",&a,&b) != 2){
printf("Invalid input,input again!a,b\n");
flush(stdin);
}
printf("\na=%d,b=%d\n",a,b);
printf("%d + %d = %d",a,b,add_without_arithmetic(a,b));
return 0;
}
补码
- 正数的补码与原码相同。
- 负数的补码等于其绝对值的各位取反,然后整个数加1的值。在绝对值和取反的过程中符号位1始终不变。
-
举例:求 -8 的补码 (小于127,当char型就可以了)
(-8)decimal ----- (10001000)binary fabs ----- (11111000)binary complement -8求绝对值的二进制表示为00001000,加上符号位 10001000,再取反(取反过程中符号位不变)11110111,再加上1,值位11111000.于是 -8 的二级制补码表示为 11111000,十六进制为 0xF8
为了便于理解和记忆,上面强调了符号位在翻转的过程中不变。于是我们给一个补码 0xA3 (char型), 于是知道这是 -93 的补码表示。方法和取负数的补码相同。 给 0x72,我们知道这就是整数114。