本文主要探讨结构体,共用体,枚举等知识。
结构体
结构体元素访问本质是指针方式,依据元素在结构体中的偏移量和元素类型进行访问
元素占字节数和类型占字节数不同,导致结构体的元素偏移量要复杂,因此结构体需要对齐访问
结构体对齐规则
结构体本身应在在4字节对齐处(占4个字节)
每个元素都对其存放
结构体对齐后的大小必须4的倍数
gcc对齐指令
#prgama pack(n)开头,#pragma pack()结尾,区间内n字节对齐,默认4字节对齐
attribute((packed)):packed取消对齐访问
attribute((aligned(n))):n字节对齐(整体结构体n字节对齐,即结构体占字节数)
offsetof宏
作用:计算结构体元素距离结构体首地址的偏移量
原理:虚拟type类型结构体,type.member访问元素,得到member相对首地址偏移量
原型:#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
(TYPE *)0
0强制类型转换TYPE指针类型(结构体变量可能不存在,解引用出错)。
((TYPE *)0)->MEMBER
指针访问member元素
&(((TYPE *)0)->MEMBER)
获得member元素地址。由于整个结构体变量的首地址是0,所以元素地址大小为偏移量
container_of宏
作用:已知结构体元素指针,得到结构体变量的指针
原理:typeof得到member类型定义成一个指针,然后用这个指针减去该元素相对于整个结构体变量的偏移量(偏移量用offsetof宏得到的),减去之后得到的就是整个结构体变量的首地址了,再把这个地址强制类型转换为type *即可
原型:
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
ptr:数据结构成员指针
type:数据结构类型
member: 在数据结构中的成员
共用体
结构体成员是独立存在,分布在不同的内存单元中
共用体中成员不独立,共用内存单元
union大小为内存最大元素大小。
大小端模式:高字节对应高地址(大端模式),高字节对应低地址(小端模式
枚举
默认值从0增加,若定义了值,则从定义值增加
宏定义和枚举的区别:枚举有关联符号封装,宏定义是离散的
枚举用于有限集合(一周7天,一月31天,一年12个月)
demo1:
结构体对齐
#include
struct info
{
int a;
char b;
short c;
};
struct info1
{
int a;
char b;
short c;
}__attribute__((aligned(1024)));
struct info2
{
int a;
char b;
short c;
}__attribute__((packed));
int main()
{
struct info n;
printf("sizeof(n) = %d\n",sizeof(n));
struct info1 n1;
printf("sizeof(n1) = %ld\n",sizeof(n1));
struct info2 n2;
printf("sizeof(n2) = %d\n",sizeof(n2));
printf("&n == %p\n",&n);
printf("n.a == %p\n",&(n.a));
return 0;
}
结果示例:
demo2:
offsetof宏和container_of宏
#include
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
struct info
{
int a;
char b;
short c;
};
int main()
{
struct info n;
n.a = 1;
n.b = 'c';
n.c = 3;
printf("&n == %p\n",&n);
printf("&(n.a) == %p\n",&(n.a));
printf("member c offset : %ld\n",offsetof(struct info,c));
printf("struct info head address: %p\n",container_of(&(n.c),struct info,c));
struct info *p = container_of(&(n.c),struct info,c);
printf("%d\n%c\n%d\n",p->a,p->b,p->c);
return 0;
}
结果示例:
demo3:
测试大小端
#include
union info
{
int a;
char b;
};
int main()
{
union info n;
n.a = 1;
printf("%d\n",(int)n.b);
if((int)n.b == 1)
{
printf("small mode\n");
}
else
{
printf("big mode\n");
}
}
结果示例:
demo4:
枚举
#include
enum judge
{
FALSE,
TRUE
};
enum judge func()
{
enum judge num;
num = TRUE;
return num;
}
int main()
{
enum judge num = func();
if(num = FALSE)
{
printf("FALSE\n");
}
else if(num = TRUE)
{
printf("TURE\n");
}
else
{
printf("union have no member\n");
}
printf("%d\n",TRUE); //1
printf("%d\n",FALSE); //0
}
结果示例: