题目:编写宏计算结构体中某变量相对于首地址的偏移。 使用offsetof计算:
#include <stddef.h>
struct S
{
char a;
int b;
char c;
};
int main()
{
printf("%d\n", offsetof(struct S, a));
printf("%d\n", offsetof(struct S, b));
printf("%d\n", offsetof(struct S, c));
return 0;
}
0
4
8
使用offsetof宏计算偏移量,参数是宏类型+成员名,一次可以计算一个成员的偏移量。 offsetof的头文件是#include <stddef.h> 。
模拟实现offsetof:
struct S
{
char a;
int b;
char c;
};
#define my_offsetof(struct_name,member_name) (int)&(((struct_name*)0)->member_name)
//struct_name是结构体类型,member_neme是成员名
//在0地址处放一个结构体,0是整数需要强制类型转换成结构体类型,struct name*指向0地址处即结构体的起始位置
//(struct name*)0表示0地址处的结构体的指针,->可以找到结构体中的成员member_name
//&取得结构体成员的地址,my_offsetof要取得的偏移量是整型,再对地址强制类型转换(int)
int main()
{
printf("%d\n", my_offsetof(struct S, a));
//printf("%d\n", (int)&(((struct_S*)0)->a)); //编译替换后
printf("%d\n", my_offsetof(struct S, b));
//printf("%d\n", (int)&(((struct_S*)0)->b)); //编译替换后
printf("%d\n", my_offsetof(struct S, c));
//printf("%d\n", (int)&(((struct_S*)0)->c)); //编译替换后
return 0;
}
0
4
8
::: tip 代码分析: 偏移量即地址之间的差值,以字节为单位,用三个成员的地址分别减去起始地址就可以得到偏移量。 假设起始位置的地址是0,结构体每一个成员的地址就是偏移量。 :::
上述代码中的结构体是位段式的。先开辟一个字节,Env_Alarm_ID占用4个比特位,Paral占用2个比特位,state没有设置字符,即需要一个字符,再开辟一个字节给state使用,然后再开辟一个字节,avail使用其中的一个比特位。在存储结构体_Record_Struct时,共开辟了3个字节,即结构体的大小是3字节。 MAX_SIZE先通过定义替换,替换后表达式变为(sizeof(struct _Record_Struct) * A+B),将结构体大小和A、B的值带入表达式,32+3=9,即pointer分配9字节。(*先替换在运算,不能先算A+B**)。
上题是内存填充的问题。 上述代码中,memset把数组puc的每一个字节都设置成0,共设置4个字节。数组puc中的内存情况如下: 代码第16行将数组puc强制类型转换成结构体指针赋给pstPinData,pstPinData是一个结构体的指针,复制后即pstPinData指向了数组puc的首元素地址。结构体指针pstPinData后将会放的是结构体的对象,对应结构体tagPIM从pstPinData指向的位置向后开辟内存块,结构体tagPIM中的成员是位段式的,类型是char,即一次向后开辟一个字节,在使用内存空间的时候从前向后逐比特位使用。 ucPim1使用一个char类型的空间即一个字节,占满了puc[0],再开辟一个字节的内存空间,ucData0从低到高占用puc[1]中的1个比特位,ucData1紧跟着占用puc[1]中的2个比特位,ucData2从低到高占用puc[1]中的3个比特位。 在对每一个结构体成员赋值时,ucPim1的二进制是010,ucData0的二进制是011,ucData1的二进制是100, ucData2的二进制是101。ucPim1的内存空间足够大,ucData0只有一个比特位,发生截断,只能存储末尾的1,ucData1有两个比特位,截断后存储00,ucData2有三个比特位,可以存储101,存储后的数组puc内存情况如下: 以%02x的形式打印数组puc的每一个字节(%x表示打印十六进制数,02表示打印两位)。1个十六进制位代表4个二进制位,如下: