struct union enum
结构体
1、结构体或者类的自身对齐值是其成员中自身对齐值最大的那个值。(所以内存小的数据类型要放一起–先写后写都行就是要放一起)
2、若结构体中有另一个结构体,且另一个结构体中有更大对齐值的数据,这用该对齐值对齐
3、数组不能直接赋值给另一个数组,但将数组写入结构体之后可以实现
4、声明一个struct可以起一个别名:
typedef struct
{
}别名;
这样定义变量的时候就不用写struct了。
5、为什么要内存对齐?
因为cpu对内存的读取是对齐的,如果内存不对齐,cpu需要读取两次才能读取到(需要拼接)。
6、位域(为了节省空间所用,似乎不影响效率,编译有优化)
形式:typename member:位域个数(一个字节8位)可以没有变量名,但仅作填充作用,不可引用
如:
struct student
{
int sex:1;
int class:2;
int :1;//无名位域,仅作填充
int id:4;
};
看似占用空间8位(一字节),但是本质还是int形式,只能按int对齐,故占用空间为sizeof(int)==4;(4字节,32位)
C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。
已知结构体成员的地址,求结构体的首地址(宏container_of)
1、可以先求偏移:
typedef struct
{
int num;
char name[12];
float score;
}student;
student s1;
char* ptr=s1.name
//如果当前是name的话,求偏移量如下
int dx=(char*)(((student*)0x0)->name)-(char*)((student*)0x0);
//pstu即为首地址
student* pstu=(student*)(ptr-dx);
2、或者可以直接使用linux内核的container_of宏定义(头文件#include<stddef.h>)
宏定义如下:
#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) );}) //根据偏移量求得首地址
//使用方法:
//pstu即为结构体首地址
student* pstu=container_of(ptr,student,name);//当前指针,结构体数据类型、成员名字
typeof()获取变量的数据类型
enum(枚举) 和 union(共用体)
#include<stdio.h>
#include<stdbool.h>
int main(int argc,char* argv[])
{
//不指定值的话默认从0开始,且后面的成员依次加1,后面成员也可以指定值,后续值根据指定值依次+1
//但是指定值之后,若值不连续的话就不能遍历了
enum Day
{
Sun,Mon,Tue,Wed,Thi,Fir,Sat
};
enum Day day;
for(day=Sun;day<=Sat;day++)
printf("today:%d\n",day);
//枚举类型的空间大小为4,但它并不是int型
printf("sizeof(enum Day day)=%d\n",sizeof(enum Day));
//共用体
union Year
{
int intYear;
char charYear[5];
};
//共用体
union Year year;
year.intYear=2022;
printf("this year is %d\n",year.intYear);
year.charYear[0]='2';
year.charYear[1]='0';
year.charYear[2]='2';
year.charYear[3]='2';
year.charYear[4]='\0';
printf("this year is %s\n",year.charYear);
//共用体所有成员共用一个内存,每次只能赋值给一个成员,输出其他成员的值为乱码
printf("sizeof(union Year year)=%d\n",sizeof(year));
printf("this year is %d\n",year.intYear);
return 0;
}