【C语言】自定义类型——结构体与内存对齐

一、什么是结构体

与int,double等内置类型不同,结构体是C语言为用户提供的一种进行多种类型定义的集合体。一言蔽之:结构体是可以一个存放多种类型的对象的集合。
例子:

int a;
double b;
long c;
//内置类型变量一旦创建,该变量将实例化在操作空间里,如果需要对其进行值的操作直接进行赋值即可
struct tag
{
    int aa;
    double bb;
    long cc;
};
//结构体将一些我们需要即将进行操作的内置或非内置类型“打包”在一起

值得一提的是,结构体类型作为一种自定义类型并不会在创建时就完成相关的值的初始化操作,而是首先创建一个“模板”,如果需要使用该结构体类型时则需要将该结构体作为变量类型进行创建结构体变量,比如需要使用tag类型的结构体创建变量时

struct tag t1;//创建一个上述声明的结构体变量不赋值,此时结构体被实例化,t1变量类型为tag类型,t1中包含 aa ,bb ,cc三种类型的变量

struct tag t2 = {1, 2.0, 255};//创建一个结构体变量t2同时赋值初始化

//在C99和C11也可以使用初始化器的方式对结构体变量进行赋值
struct tag t1 ={ .aa = 1, 
                 .bb = 2.0, 
                 .cc = 255};

结构体内的变量的声明可以是任何类型,如:数组、指针、其他结构体变量等等。

struct Node
{
     char name[15];
     int age;
     struct* Node next;
}typedef Node;
//typedef重定义struct Node为Node,即进行定义结构体变量时使用Node作为关键字即可

Node n1 = {"Li Ming",
            15,
            NULL};//创建结构体变量n1并进行初始化

二、结构体内存对齐

上述描述中以及了解到结构体是一种“超级数组”,结构体内可以存储各种类型的变量。但是问题也接踵而至,一个内置类型如int类型我们通过sizeof操作可以知道int类型的大小为4个字节,double类型为8个字节。那么一个结构体类型所占的存储空间又是多少呢?有人突发妙想,认为只需将我们认识的类型进行堆砌即可。但下述例子有力的回应了这种观点的错误。

struct tag1
{
    int aa;
    double bb;
    long cc;
};
struct tag2
{
    double bb;
    int aa;
    long cc;
};

struct tag1struct tag2内部所声明的变量类型完全相同,只有内部顺序不同,依照上述观点,你可以得出tag1与tag2所占空间均为4+8+8=20字节的结论。但是我们分别使用sizeof对tag1和tag2进行操作就会发现:tag1所占空间为24个字节(编译器对齐数为8)、tag2所占空间为64个字节(编译器对齐数为8)说明上述观点是存在错误的。这是因为由于编译器移植等性能原因,结构体类型的存储方式并不能完全依照内置类型方式进行存储。存在结构体内存对齐的存储方式以便代码高效运行。

1、 结构体内存对齐规则

  • 结构体的第一个成员永远放在结构体起始位置偏移量为0的位置
  • 从第二个成员开始,结构体成员总是放在对齐数的整数倍处(对齐数=编译器默认对齐数和自身大小的较小值)
  • 结构体的总大小必须是各个成员的对齐数中最大那个对齐数的整数倍
  • 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍处

那么在上述的tag1中计算规则应为4+(4)+8+8=24,其中括号中表示对齐占位字节

tag2中计算规则应为8+4+(40)+8+(4)=64,
可以看出即使结构体存放相同的变量类型,顺序不同,所占空间将会有显著差异
所以,一般情况下,我们在定义结构体时应使用占位空间从小到大的形式对变量进行定义。

2、为什么存在内存对齐?

  1. 平台原因:不是所有硬件平台上都能访问地址上的任意数据;某些硬件只能特定地读取数据
  2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存访问仅需要一次。

这就是结构体与它的内存对齐,希望这篇文章对你有所帮助!

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JasonTuring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值