1、写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明。考察:offsetof宏的实现
offsetof宏的原型如下:
代码语言:javascript复制#include <stddef.h>
size_t offsetof(type, member);
但请注意,实际上offsetof是一个宏,而不是一个函数。
它接受两个参数:一个结构体类型和一个该类型中的成员名称,并返回该成员在结构体中的字节偏移量。
使用举例:
代码语言:javascript复制#include <stdio.h>
#include <stddef.h>
typedef struct {
int a;
char b;
double c;
} MyStruct;
int main() {
printf("%zun", offsetof(MyStruct, b));
printf("%zun", offsetof(MyStruct, c));
return 0;
}
回归题目,
我们可以将0转换成一个结构体类型的指针,相当于这个结构体的首地址为0,所以结构体元素的偏移量就是相对于0的偏移量。
因为首元素地址为0,结构体类型指针指向结构体成员的地址,将该地址强转成size_t类型,就能得到这个偏移量了。
代码语言:javascript复制#include<stdio.h>
struct A
{
char a;
int b;
};
#define OFFSET1(STRUCTtype,member) (size_t)&(((STRUCTtype*)0)->member)
//不能用成员指针减结构体起始位置地址的方式去计算偏移量
// #define OFFSET2(STRUCTname,member) (size_t)(&(STRUCTname.member) - &STRUCTname)
int main()
{
struct A str = { 'a',2024 };
printf("%zdn", OFFSET1(struct A, b));
//printf("%zdn", OFFSET2(str, b));
return 0;
}
2、写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。
这里我画了一个图,能够更清楚展示
假设是在32位的环境下,
将一个整数与01010101……(共32位)进行按位与运算,能够将它二进制的奇数位上的0或1保留下来,偶数位上的都变成0;
与10101010……(32位)进行按位与运算,能够将它二进制的偶数位上的0或1保留下来,奇数位上的都变为0;
要想奇数位与偶数位互换,可以将保留下奇数位的二进制进行左移,最右边补0;将保留下偶数位的二进制进行右移,最左边补0;然后进行按位或运算,就能得到交换后的二进制了。
代码语言:javascript复制#define Swap(n) (((n&(0x55555555))<<1)|((n&(0xaaaaaaaa))>>1))
int main()
{
int n = Swap(11);
printf("%dn", n);
return 0;
}