笔记24-3(C语言进阶 程序环境和预处理练习)

目录

注:

练习一

写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换

练习二

写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明 


 

注:

        本笔记参考:B站up 鹏哥C语言的视频


练习一

写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换

假设

整数二进制位的最右侧那一位为第1位。

分析

我们需要做到的就是将奇数位上的二进制数字和这个奇数位左边一位的哪一个偶数位数字进行交换,即:

如果我们交换这个10的二进制位,我们就会得到:

即5的二进制位。

这就相当于:

  • 偶数位右移1位。
  • 奇数位左移1位。

所以我们需要先分开奇数位和偶数位的二进制数字,譬如15的二进制位:

如果把交换后的二进制位相加,可以发现结果与原本的15相同。

那么我们要如何分离二进制序列的奇数位和偶数位呢?答案还是按位与

假设我们要处理的二进制序列是 11111111 11111111 11111111 11111111 。我们让这个二进制序列按位与另一个二进制序列:

  1. 要求这个二进制序列只有在按位与到奇数位时,结果是1。
  2. 要求这个二进制序列只有在按位与到偶数位时,结果是1。

而按位与只有当两者相同位置上数字均为1时,结果才会是1.也就是说,只要有一个二进制序列只有奇数位都是1,那么此时按位与,得到的结果就会是目标二进制序列的奇数位上的数字。

把上述的认识写成代码:

int ret = ((num & 0xaaaaaaaa) >> 1) + ((num & 0x55555555) << 1);

接下来就是提供宏来实现它了:

#define SWAP(N) ((N & 0xaaaaaaaa) >> 1) + ((N & 0x55555555) << 1)

源代码

#include<stdio.h>
#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<stdio.h>
#include<stddef.h>

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 假设成了这一结构体的起始地址,然后通过结构体指针访问每一个成员,最后把得到的地址之差进行强制类型转换,就得到了偏移量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值