结构体内存对齐和修改默认对齐数

目录

一.结构体

前言

1.定义

2.结构体声明

3.举例

a.数据结构

以数组为例:

​编辑

 4.结构体嵌套

二.内存对齐

1.结构体对齐规则

2.举例计算

3.内存对齐的意义何在?

优点:

三.修改默认对齐数

 四.offsetof函数(返回成员偏移量)


一.结构体

前言

内置类型
char
short
int

float

double
复杂对象
人,书
自定义类型
结构体,联合体,枚举

1.定义

1.在编程中,结构体(Structure)是一种可以存储不同类型数据项的复合数据类型。它是一种用户自定义的数据类型,用于封装一组相关联的不同类型的数据项。

2.结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

3.理解结构体,我们可以类比一下数组(一组相同类型元素的集合),而结构体是一组不同类型的集合。

下面介绍的是C语言中的结构体。

2.结构体声明

下面我们声明了一个结构体,并对它进行定义。

一个学生的结构体,里面包含他的名字和年龄。在结构体末尾进行了结构体重命名和定义。

而s1是struct Stu类型的变量。其中包括两个成员,分别是name,age。在后续定义新变量,可以省略前面 的struct,Stu s2即可。

// 在C语言中定义一个结构体  
struct Stu {  
    char name[20];  
    int age;    
}s1 = {"zhangsan",20};

3.举例

a.数据结构

数据在内存中的存储结构
线形
顺序表
链表
树形
二叉树
以数组为例:

1.当我们挨个存储,即顺序存储(内存中开辟连续的空间),一个挨着一个。想要找那个数字,只需要按顺序查找就行。

2.如果内存中没有开辟连续的空间,仍想要通过1找到2,通过3找到4,但他们的存储位置是零散的。要想解决以上问题,我们需要用到结构体。

3.通过1-->2,1所在的内存空间,不但要存储1数据本身,还要存储一个指向2所在空间的指针。以此类推,当到最后一个数据时,不再存储指向数据的指针,而是存储一个空指针。每个数据都按照下面这个结构体来存储。

typedef struct Node
{
   int a;
   struct Node* next;
}Node;

 4.结构体嵌套

struct number//存储学生学号和编号
{
	int ID;
	char ch;
};
struct grade//存储学生语数英三科成绩
{
	int language;
	int math;
	int english;
};
struct message//存储学生的姓名和年龄
{
	char name[20];
	int age;
};
struct Stu//存储以上三个结构体的内容(即结构体嵌套)
{
	struct message a;
	struct number b;
	struct grade c;
};

int main()
{
	struct Point p2 = { 3,4 };
	struct Stu s1 = { {"zhangsan",18} ,{5,'A'},{90,80,95} };
	printf("姓名:%s 年龄:%d\n", s1.a.name,s1.a.age);
	printf("学号:%d 总评:%c\n", s1.b.ID, s1.b.ch);
	printf("语文:%d 数学:%d 英语:%d\n", s1.c.language, s1.c.math, s1.c.english);
	return 0;
}

二.内存对齐

1.结构体对齐规则

1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的一个对齐数与该成员大小的较小值。
 Vs中默认的值为8. 
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

2.举例计算

1.声明两个结构体S1和S2,定义两个结构体s1,s2。分别计算s1,s2的大小

struct S1
{
	char c1;
	int i;
	char c2;
};

struct S2
{
	char c1;
	char c2;
	int i;
};

int main()
{
	struct S1 s1;
	struct S2 s2;
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s2));
	return 0;
}

2.s1中有三个成员变量,类型分别为char,int,char,为什么它们大小相加是12,而不是6呢?

因为它们在内存中所占大小,是有规则限制的。

下面,我画图给大家解释一下。

结构体嵌套,又该如何计算呢?大家请看下面图片。 

struct S1
{
	char a;
	double b;
	int c;
};

struct S2
{
	char i;
	struct S1 s1;
	int j;

};

int main()
{
	printf("%d\n", sizeof(S2));
}

 s2中嵌套了s1

3.内存对齐的意义何在?

内存对齐是一种提高内存访问效率的方法,它在许多编程语言和系统架构中都被广泛使用。它的主要目标是通过减少内存访问延迟,从而提高程序的性能。

优点:

  1. 提高内存访问效率:在许多计算机架构中,内存的访问速度是有限的。如果数据在内存中的位置是随机的,那么CPU需要花费额外的时间来寻找数据,这被称为内存访问延迟。然而,如果数据按照特定的对齐规则进行存储,CPU的内存控制器就可以更有效地预取数据,从而减少内存访问延迟。
  2. 提高硬件效率:许多现代CPU都有专门为对齐数据而设计的内部机制。例如,一些CPU具有专门的对齐引擎,可以更快地处理对齐的数据。如果数据没有对齐,CPU可能需要进行多次访问内存才能获取到完整的数据,这会降低CPU的效率。
  3. 减少数据依赖:在某些情况下,如果数据没有对齐,可能会导致一些特定的CPU指令无法使用,从而增加了数据的依赖性。这可能会使得程序的并行度降低,从而影响程序的性能。
  4. 提高程序的稳定性:在某些情况下,不对齐的内存访问可能会导致硬件异常或者程序崩溃。例如,在某些架构中,访问未对齐的数据可能会导致所谓的"alignment fault"。

因此,编程时进行内存对齐不仅可以提高程序的性能,还可以提高程序的稳定性和可维护性。在编写代码时,应该尽可能地遵循内存对齐的最佳实践。

三.修改默认对齐数

#pragma pack(4)//修改默认对齐数
struct S
{
	int i;
	double d;
};
int main()
{
	printf("%d\n", sizeof(struct S));
}

 四.offsetof函数(返回成员偏移量)

offsetof (type,member)//类型,成员名
struct S1
{
	char c1;
	int i;
	char c2;
};

struct S2
{
	char c1;
	char c2;
	int i;
};

int main()
{
	struct S1 s1;
	struct S2 s2;
	printf("%d\n", offsetof(struct S1,c1));//返回成员变量的偏移量
	printf("%d\n", offsetof(S1,i));
	printf("%d\n", offsetof(S1, c2));
	return 0;
}

                                            看到这里,不妨点个攒,关注一下吧!

最后,谢谢你的观看。 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值