首页 > 其他分享 >【C】怎样利用宏交换一个整数的二进制奇偶位?

【C】怎样利用宏交换一个整数的二进制奇偶位?

时间:2023-03-23 16:01:23浏览次数:33  
标签:奇偶 奇数 二进制 整数 偶数 int ADD define

一、问题解剖

交换二进制奇偶位,划分为两个步骤:


1、偶数位数据右移;

2、奇数位数据左移;


获取奇偶位数据

例:

int a = 23;

二进制表示为:(对奇偶位分别标色)

【C】怎样利用宏交换一个整数的二进制奇偶位?_数位

交换后为:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数位_02

偶数位

采取二进制中偶数位全为1的数据,利用按位与&,便可获得其偶数位数据:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_03

奇数位

采取二进制中奇数位全为1的数据,同理可得奇数位数据:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_04

数据移位

偶数位左移1位便会变成奇数位:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数位_05

同理,奇数位右移1位便移到偶数位:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_06

数据合成

将奇偶位数据依照按位或 | 的规则合成,便得交换后的数据:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_07


二、代码实现

获取偶数位数据,将a与0xaaaaaaaa按位与&便得,随后右移1位;获取奇数位数据,将a与0x55555555按位与&得,随后左移1位;再将奇偶位得数据按位或,便可得;


具体实现:
#define SWAPB(x) ((x & 0xaaaaaaaa)>>1)|((x & 0x55555555)<<1)
int main()
{
  int a = 23;
  int b = SWAPB(a);
  printf("a = %d b = %d\n", a, b);
  return 0;
}


测试得:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_08

测试负数 -1:

由于整型在内存中以补码存储,而负数得原码与补码不同,先计算补码:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_09

-1在内存中存储时,每一个bit位上都为1,都已交换二进制奇偶位时,应不改变结果,测试如下:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数位_10



三、使用#define应注意


多用空格,提高代码可读性?

使用#define时,大可不必如此。

定义宏时,方式如下:

#define name( parament-list ) stuff

其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就都会被解释为stuff的一部分;


加上分号,代码更严谨?

与之相反,使用#define时,加上分号,易使代码出现难以察觉的错误,如下面一段代码:

#define MAX 100;

int main()
{
	int a = 0;
	if (1)
		a = MAX;
	else
		a = 1;
}

一眼看过去貌似合理,但编译器此时便会报错,而且提示更让人摸不着头脑;

【C】怎样利用宏交换一个整数的二进制奇偶位?_#define_11

明明语句都正常在,为什么提醒要加一个语句呢?

原因便是,使用#define时,编译器会在预编译阶段对#define定义的符号进行替换,我们打开编译的文件,比对发现, a = MAX 被替换成了a = 100;;,从而导致else语句失去了开始的if,缺乏语法结构而报错;

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_12

因此在使用#define时,切勿随便使用分号 ;


定义宏,代码越精简越好?

代码的艺术,越精简越优雅,但定义宏时的优雅,极有可能导致代码正确性的损失,如下:

#define ADD(x, y) x+y

int main()
{
	int a = 2;
	int b = 3;
	int c = 4;
	printf("%d ", c * ADD(a, b));
}

我们定义加法宏,a = 2, b = 3, c= 4, 2+3=5,4×5 = 20,结果应当输出20,真的如此吗?

【C】怎样利用宏交换一个整数的二进制奇偶位?_二进制_13

我们看到输出了11,还是因为#define定义时,并不会先计算再传值,而是整体替换,在预编译时c * ADD(a, b)会被替换成c * a + b,4×2+3,结果自然是11,那我们添加括号呢?

#define ADD(x, y) (x+y)
#define SQUARE(x, y) (x * y)

int main()
{
	int a = 2;
	int b = 3;
	int c = 4;
	printf("%d\n", c * ADD(a, b));
	printf("%d\n", SQUARE(a + 1, b));
}

ADD的问题解决了,增加括号便好,那以同样的方式定义乘方SQUARE,同时增加一行乘方的测试函数,a = 2 , 2+1 = 3, 3×3 = 9,那么会不会输出9呢?

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_14

结果不然,这是因为SQUARE(a + 1, b)会被替换成a + 1 * b,于是输出5。

所以,定义数值计算的宏时,对变量与每一次计算,都需添加括号,避免由于参数中的操作符或邻近操作符之间优先级的不同,出现不可预料的相互作用。如下:

【C】怎样利用宏交换一个整数的二进制奇偶位?_数据_15

不可出现递归

如上解读,在预编译阶段,#define定义的字符被替换后,可以观察到其对应的语句会被删除,若采取递归,则会导致第二次使用时,其语句不能被编译器识别。

标签:奇偶,奇数,二进制,整数,偶数,int,ADD,define
From: https://blog.51cto.com/u_15423682/6145625

相关文章