结构体、位段(位域)、联合体、枚举类型大小计算及分析

1.结构体

void test1()
{
	typedef struct
	{
		int i;
	}s;
	typedef struct 
	{
		char c1;//1
		char c2;//1
		int i;//4
	}s1;//8
	typedef struct 
	{
		char c1;//1
		int i;//4
		char c2;//1
	}s2;//12
	typedef struct 
	{
		char c2;//1
		double d;//8
		int i;//4
	}s3;//24
	typedef struct
	{
		char c1;//1
		s s;//4
		double i;//8
	}s8;//16
	typedef struct 
	{
		char c1;//1
		s1 s1;//8
		int i;//4
	}s4;//16
	typedef struct
	{
		char c1;//1
		s3 s3;//24
		int i;//4
	}s7;//40
	/*typedef struct
	{
		char c1;//1
		int i;//4
		s3 s3;//24
	}s7;//32*/
	printf("s->%d\n", sizeof(s));
	printf("s1->%d\n", sizeof(s1));
	printf("s2->%d\n", sizeof(s2));
	printf("s3->%d\n", sizeof(s3));
	printf("s4->%d\n", sizeof(s4));
	printf("s7->%d\n", sizeof(s7));
	printf("s8->%d\n", sizeof(s8));
	printf("char->%d\n", sizeof(char));//1
	printf("short->%d\n", sizeof(short));//2
	printf("int->%d\n", sizeof(int));//4
	printf("long->%d\n", sizeof(long));//4
	printf("char*->%d\n", sizeof(char*));//4
	printf("double->%d\n", sizeof(double));//8
	printf("long long->%d\n", sizeof(long long));//8

	/*typedef struct node
	{
		int data;
		 node* next;//必须加上struct,此时还没重命名
	}node;*/
	/*typedef struct node
	{
		int data;
		struct node* next;
	}node;*/
	/*struct node
	{
		int data;
		struct node next;//不能直接包含自身,引发递归定义了/
	};*/
	/*typedef struct stu//(不声明时为匿名结构体)
	{
		int data;
	}s7;*///重命名
	//s1 s2;//重命名
	//struct stu s2;
	/* struct stu//(不声明时为匿名结构体)
	{
		int data;

	}s5;//定义一个自定义类型的变量
	 s5.data;*/
	 /*struct //(不声明时为匿名结构体)
	 {
		 int data;
	 }s6;
	 s6.data;*/
}

1.结构体是一个自定义类型,内部数据类型独有内存空间,和联合体(共用体要做好区分)。

2.计算机结构体大小需要内存对齐,为什么需要内存对齐呢?
由于32位处理器一次可以取出32个比特位(4字节),所以取数据的时候不是一个字节一个字节的取,如果数据类型小于4字节的话,会取出来然后分割,而且如果数据连续存储,就会更加麻烦,所以引入内存对齐,以空间换时间。
在这里插入图片描述
3.如何进行内存对齐?
默认对齐数(win 8,linux 4)#pragma pack(n) n=1 2 4 8 16
第一位默认0开始
之后的数据要对齐,对齐数=min(默认对齐数,当前数据大小)
结构体总大小为最大对齐数的整数倍。
嵌套了结构体的话(不能自引用,指针除外),总大小为最大对齐数的整数倍(max(结构体,数据类型)),详情留意s3 s4 s8,s7计算。
在这里插入图片描述
在这里插入图片描述

2.位域

void test2()
{
	struct A
	{
		int _b : 5;//4
		int _c : 4;//4
	};//4
	struct B
	{
		char _a : 3;
		char _b : 4;//1
		char _c : 5;//2
		int _d : 5;//4
	};//8
	struct C
	{
		char _a : 3;
		char _b : 4;//1
		char _c1 : 5;//2
		char _c2 : 5;//3
		char _c3 : 5;//4
		char _c4 : 5;//5
		int _d : 5;//9
	};//12
	printf("%d\n",sizeof(struct A));//4
	printf("%d\n", sizeof(struct B));//8
	printf("%d\n", sizeof(struct C));//12
}

位域是控制类型所占的比特位。(char 不能大于8,int不能大于32),小于该类型的比特位可以拼接。
也会存在内存对齐,对齐为最大类型的整数倍,参见B,C.

3.联合体

void test3()
{
	union un1
	{
		char c;
		int i;
	}u1;
	union un2
	{
		char c[5];
		int i;
	}u2;
	printf("%d\n", sizeof(u1));//4
	printf("%d\n", sizeof(u2));//8
	u1.i = 1;
	if (u1.c == 1)
	{
		printf("小端机\n");
	}
	else
	{
		printf("大端机\n");
	}
	printf("%d\n", sizeof(u1));
}

联合体成员共用一块内存,大小为最大数据类型,适用于不常同时出现的数据,有利于节省内存空间。
我们可以通过赋值来验证这个,同时可以通过这个方法,来验证大小端。
同时联合体也会内存对齐,u2的最大为5,但是最大对齐数为4,所以要对齐为8.

4.枚举类型

void test4()
{
	enum day
	{
		HOUR,
		MINUTE,//递推
		SECOND=5,//可以给数据大小
	};
	printf("%d\n", HOUR);
	printf("%d\n", MINUTE);
	printf("%d\n", SECOND);
}

枚举类型常量,和宏的区别
1.可读性好。
2.有类型检查,安全,便于调试。
3.封装性好,防止命名污染。
4.使用方便,可以一次定义好几个,同时递推数据大小,默认从0开始,也可以自己给值。

int main()
{
	//test1();//结构体
	//test2();//位段(位域)
	//test3();//联合体共用内存空间,大小为数据类型大的所占的空间。
	//test4();//枚举常量
	system("pause");
	return 0;
}

通过这个整理,我对联合体,结构体,枚举类型,位段有了新的理解,初学如果有错误,欢迎大家指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章