目录
注:
练习一
写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换
练习二
写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
本笔记参考:B站up 鹏哥C语言的视频
假设
整数二进制位的最右侧那一位为第1位。
分析
我们需要做到的就是将奇数位上的二进制数字和这个奇数位左边一位的哪一个偶数位数字进行交换,即:
如果我们交换这个10的二进制位,我们就会得到:
即5的二进制位。
这就相当于:
所以我们需要先分开奇数位和偶数位的二进制数字,譬如15的二进制位:
如果把交换后的二进制位相加,可以发现结果与原本的15相同。
那么我们要如何分离二进制序列的奇数位和偶数位呢?答案还是按位与。
假设我们要处理的二进制序列是 11111111 11111111 11111111 11111111 。我们让这个二进制序列按位与另一个二进制序列:
而按位与只有当两者相同位置上数字均为1时,结果才会是1.也就是说,只要有一个二进制序列只有奇数位都是1,那么此时按位与,得到的结果就会是目标二进制序列的奇数位上的数字。
把上述的认识写成代码:
int ret = ((num & 0xaaaaaaaa) >> 1) + ((num & 0x55555555) << 1);
接下来就是提供宏来实现它了:
#define SWAP(N) ((N & 0xaaaaaaaa) >> 1) + ((N & 0x55555555) << 1)
源代码
#include
#define SWAP(N) ((N & 0xaaaaaaaa) >> 1) + ((N & 0x55555555) << 1)
int main()
{
int num = 10;
int ret = SWAP(num);
printf("%d\n", ret);
return 0;
}
提示
参考图
------
参考offsetof宏的实现
计算结构体成员相对于起始位置的偏移量。
offsetof宏的使用例
#include
#include struct A { int a; short b; int c; char d; }; int main() { printf("%d\n", offsetof(struct A, a)); printf("%d\n", offsetof(struct A, b)); printf("%d\n", offsetof(struct A, c)); printf("%d\n", offsetof(struct A, d)); return 0; } 打印结果
分析
本题实际上可以看作模拟实现宏offsetof。接下来设定我们自己所写宏名字是OFFSETOF。那么首先:
#define OFFSETOF(struct_name, mem_name)
接下来就要首先宏的功能,那么第一个问题,offsetof宏是如何实现的?、
一般而言,只要将成员所占空间的起始地址减去偏移量为0的地址(即结构体起始地址)就可以得到偏移量。
而如果我们就假设结构体的起始地址就是 0 ,那么之后的成员所在地址就正好是该成员的偏移量。根据这一思路,得到:
#define OFFSETOF(struct_name, mem_name) (int)&(((struct_name*)0) -> mem_name)
这就是我们写成的宏。
之所以可以这样写,是因为此时的 struct_name 就是一个结构体类型的名称,而 struct_name* 就是这种结构体类型的指针。通过这串代码,先把 0 假设成了这一结构体的起始地址,然后通过结构体指针访问每一个成员,最后把得到的地址之差进行强制类型转换,就得到了偏移量。