【C语言】自定义类型之结构体(内存对齐)+位段

一.结构体

结构是一些值的集合,称为他的成员,值的类型可以不同(相当于内部成员类型不同的数组)。
1.结构体的声明

struct tag {  //tag为结构体名字
member-list ;  // 成员必须在声明时一一列举;(包括类型与名字)
} variable-list ;// 创建具体变量

例1:
这个声明创建了一个x[20]结构体数组,y结构体指针。但没有为结构体命名,所以在创建相同结构体类型变量必须重新声明

	struct {
		int a;
		char b;
		float c;
	}x[20], *y;

例2:
这个声明没有创建变量,但命名了结构体,所以可在创建变量时直接用struct+结构体名字(stu)+变量名;

	struct stu{
		int a;
		char b;
		float c;
	};
 struct stu x;// 定义了一个x结构体变量

例3:
运用typedef创建新类型。与例2区别在于创建变量时直接用结构体名字(stu)+变量名;

	typedef struct {
		int a;
		char b;
		float c;
	}stu;
stu x;// 定义了一个x结构体变量

2.结构体访问

	struct {
		int a;
		char b;
		float c;
	}x[20], *y;

A.直接访问: 通过**点操作符(.)**访问,左边为结构变量名,右边为访问成员名。

x[5].a;

B.间接访问:通过结构体指针进行访问。(->),左边为指针名,右边为访问成员名。

y->a;

3.结构的自引用: 必须使用指针进行自引用;

	struct stu {
		int a;
		char b;
		struct stu *str;
	}y;

4.结构的初始化

struct stu {
		int a;
		char b;
		int a[2];
	}y={2,'a',{1,3}};

或者

	typedef struct{
		int a;
		char b;
		int c[2];
	}stu;
	stu y = { 2,'a',{1,3} };

5.结构体传参:(使用地址传参)
节省栈上空间!
6.内存对齐(超级重要)
对齐规则:

  • 第一个成员的首地址为0
  • 每个成员的首地址是自身大小的整数倍
    补充:其实需要自身大小与系统默认对齐数进行比较取最小值。但vs中最小对齐数为8,大于等于最大的数据类型,可以忽略。
  • 以整个结构体中(包括子结构体)最大长度的类型为标准进行对齐【整体对齐】

	struct stu {
		char a;
		double b;
		char c;
		int d[2];
		int * e;
		char f;
	}y;
	printf("%d\n", sizeof(y));
	printf("%p\n", &y.a);
	printf("%p\n", &y.b);
	printf("%p\n", &y.c);
	printf("%p\n", &y.d);
	printf("%p\n", &y.e);
	printf("%p\n", &y.f);

在这里插入图片描述在这里插入图片描述
分析:

  • 第一个成员地址从0开始,为char型,所以占一个字节,此时下个空地址为1;
  • 第二个成员为double型,占8个字节,不可以从1开始,所以内存对齐到8。此时下个空地址为16;
  • 第三个成员为char型,占一个字节,可以从地址16开始,不需要内存对齐,此时下个空地址为17;
  • 第四个成员为int型数组,占4*2个字节,不可以从17开始,需内存对齐到20,,此时下个空地址为28;
  • 第五个成员为指针,占4个字节,可以从28开始,不需要内存对齐,此时下个空地址为32;
  • 第六个成员为char型,可以从32开始,不需要内存对齐,此时下个空地址为33;
  • 整个结构体此时占33个字节,最大对齐数为8,需内存对齐至40;

二.位段(节约资源,但不可跨平台)

位段声明与结构体类似,不同点在于:
1.位段成员必须为int,signed int或者unsigned int,char;
2.位段成员名后必须跟** : 加一个数字 **
例:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
struct B
{
	char _a : 2;
	char _b : 5;
	char _c : 2;
	char _d : 3;
};
struct C
{
	int _a : 30;
	int _b : 30;
	int _c : 10;
	int _d : 30;
};
	printf("%d\n", sizeof(struct A));//8
	printf("%d\n", sizeof(struct B));//2
	printf("%d\n", sizeof(struct C));//16

地址分析图如下:
1.
在这里插入图片描述

在这里插入图片描述
3.
在这里插入图片描述
缺陷(不可跨平台):

  • int位段被当成有符号还是无符号不确定的。
  • 位段中最大位数的数目不能确定。(16位机器最大16,32位机器最大32,写成27在16位机器会出现问题。)
  • 位段的成员在内存中内存分配从左向右还是从右向左尚未定义。
  • 当一个结构体包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余时,是舍弃还是利用的,这也是不确定的。
发布了53 篇原创文章 · 获赞 49 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43550839/article/details/99286398