允执 引商刻羽,杂以流徵

练习和训练场

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. 将加法运算转换为位操作

思路是

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;
}

补码

点击查看评论
推荐到豆瓣

Blog

Opinion

Project