结构体进阶知识 struct内存对齐(笔试面试常考)

Posted -YIN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体进阶知识 struct内存对齐(笔试面试常考)相关的知识,希望对你有一定的参考价值。


什么是结构体?

   相信对于已经学习或了解过C语言知识的伙伴们,对于结构体这个名词肯定不陌生,但是结构体相关知识你都了解吗?继续往下学习或者复习巩固一下吧。

结构体定义 及 声明

结构体定义:结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据称为结构型数据的“成员” ,其描述了一块内存区间的大小及解释意义。

这样比较抽象的定义看完是不有点似懂非懂。
  

举个例子:结构体的声明

1
struct student                          struct tag       //类型名
{                                       {
	char name[10];      姓名                       
	char sex[3];        性别               member-list    //成员列表
	int age;            年龄
	char num[20];       学号            }variable-list;  //结构体类型定义变量
} s;        //必须要带分号

这个声明创建了一个名叫 s 的变量,s包含四个成员:{字符数组name、sex、num和整形 age}。

这是对于一个学生结构体类型的声明,其中 student 称为结构体的 类型名(标志);其中如 name,age等这些叫做结构体成员列表; 而xiaoming则是在声明结构体类型时定义的结构体变量(也可以在结构体声明后定义:struct student xiaoming)。

typedef struct

也可以用 typedef 对结构体类型进行重命名,这种写法比较常见,如下student结构体重命名为 stu更方便记忆与使用。即 stu 就是 struct student(这里与上面声明写法比较容易混淆在我当时刚学习时就一直没有搞懂)

2
typedef struct student
{
	char name[10];      //姓名
	char sex[3];        //性别
	int age;            //年龄
	char num[20];       //学号
}stu;

这时再看一遍定义,其实在C语言中结构体是一种数据结构,是一种由程序设计人自定义的数据类型,其中结构体成员列表其实可以理解为抽象出为数据的事物属性的集合;如上面的结构体 student 表示学生这一类型,即有姓名,性别,年龄和学号等属性组成的学生这一自定义类型,便是结构体。(自我见解,欢迎指正)
  
  

结构体变量的定义及初始化

有了上面的结构体和,如何对结构体变量进行定义与初始化

struct student s1 = { "zhangsan", "男", 21, "001" };    
  
stu s2 = { "xiaoming", "男", 20, "002" };
这两种初始化方式等价

注意:要在定义变量的同时赋初值,而不能先定义后赋值。
   
   

结构体内存对齐

那么c语言中,每种类型在相同平台都有固定的大小


(windows 32位平台)运行结果
   
   

那结构体在内存中是如何实际存储的呢?s1 和 s2 大小相等吗?分别为多少?

3
struct S1
{
    char a;        // 1
    char b;        // 1
    int c;          // 4
};
printf("%d\\n", sizeof(struct S1));4
struct S2
{
    char a;        // 1
    int  b;        // 4
    char c;       // 1
};
printf("%d\\n", sizeof(struct S2));

S1 与 S2类型成员一样,但占用空间大小却不同。
所以在设计结构体时既要满足对齐,又尽可能节省空间,将空间小的成员尽量集中到一起

为什么存在内存对齐?

1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。因为处理器读写数据,并不是以字节为单位,而是以块(2,4,8,16字节)为单位进行的。如果不进行对齐,那么本来只需要一次进行的访问,可能需要好几次才能完成,导致效率低下。

所以内存对齐便是用少量空间换取时间来提高效率的一种方式
   
   

对齐规则

1.第一个成员一定对齐,位于结构体变量偏移量为0的地址处。

!  对齐数 = 编译器默认值成员自身大小 两者较小值

2.其他成员要对齐对齐数的整数倍的地址处。
( 整数倍(最小值) = 当前起始偏移量 / 对齐数 )
3.结构体 总大小必须为最大对齐数(每个成员都有一个对齐数)的整数倍 。
( 当前存入变量的起始偏移量能否整除变量自身大小 )
4. 如果嵌套了结构体的情况,先按规则计算出嵌套的结构体大小,最后结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
   
   

如何计算内存大小

   遵循对齐规则进行计算

例题:

struct S3
{
	double d;
	char c;
	int i;
};

struct S4
{
	char a;
	struct S3 s3;
	int arr[5];
	char *p[3];
	char(*q)[4];
};

解析:


参考结果:(最大对齐数为8) S4 = 1 + (7)+ 16 + 20 + 12 + 4 + (4) = 64.

运行截图

修改默认对齐数

通过#pragma预处理指令,将默认对齐数修改。

5
#pragma pack (4)   //设置默认对齐数为 4
struct S1
{
    char a;        // 1
    char b;        // 1
    int c;          // 4
};

#pragma pack ()  //取消设置的对齐数,重置为默认

   
   
   
   
码字不易,关注三连支持一波!

以上是关于结构体进阶知识 struct内存对齐(笔试面试常考)的主要内容,如果未能解决你的问题,请参考以下文章

C语言精要总结-内存地址对齐与struct大小判断篇

C语言精要总结-内存地址对齐与struct大小判断篇

浅谈结构体,结构体内存对齐

转载c++面试题

C++基本知识点总结(网摘)

C语言进阶自定义类型详解(结构体+枚举+联合)