结构体的内存对齐问题探索

来源:互联网 发布:手机淘宝图片最佳尺寸 编辑:程序博客网 时间:2024/05/24 04:03

    在讨论这个问题之前我觉得先回顾一下结构体的各项性质。

    1、结构体如何定义?

  • struct A

{

int a;

int b;

};

A a1 = {1,2};

  • struct B b1

{

.a = 1,

.b = 2

};

  • struct C c1

{

       a:1,

b:2

};

第一种比较常用,由它也可以衍生出不少初始化的方法:

struct A
{
int a;
int b;
}a1 = {1,2};

或者

struct 
{
int a;
int b;
}a1 = {1,2};

在或者也可以直接使用typedef进行定义和更名。

在第二种和第三种初始化方法中成员的顺序可以改变,第一种是不可的。


2、为什么要使用结构体?

   其实这个问题就要从数组的特点开始说起,因为数组拥有:相同类型的数据,连续分配的内存并且内存大小一旦确定就无法改变,数组的名字为一个指针,代表的是这个数组首元素的地址。

   那么当我们要使用一个稍微复杂的数据集合体,比如学生这个个体,包含了学生的学号姓名班级成绩等信息,这样用一个数组是无法表述的,这个时候就引入了结构体类型,结构体类型可以定义一个包含这些所有数据类型的变量,从而实现对这个整体的操作。


3、接下来我们来谈一谈结构体的内存对齐问题。

   现在有这样一个结构体类型:

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


如果按照常理来计算它的内存,应该是4+1+8=13B,但是用sizeof计算内存时,测得结果是16,这是怎么回事?我查了网上的资料了解到,结构体在分配内存的时候涉及到”内存对齐“的问题。那么什么是”内存对齐“呢?


这里我引用了百度百科对内存对齐的解释:内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。

具体的规则下面会有讨论,这里还要先说一下为什么要有内存对齐呢,像上面一样直接分配13个字节不就完了嘛?

大部分资料解释都是硬件原因,本人对硬件也不是很了解,比如说ARM单片机在取址的时候是32位取,也就是一次4个字节,如果不内存对齐,那么将会大大减小取址的效率,有的甚至直接抛出硬件异常,也就是所谓的平台移植问题。还有一点就是数据结构尤其是栈,应该最大限度在自然边界上对齐,不然处理器需要访问两次才能完成操作,效率受到影响。


那么如何内存对齐呢?

有三个规则:

1、结构体中的第一个成员的首地址也即是结构体变量的首地址。

2、结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。

3、结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n与结构体中最大数据类型的成员大小的最小值)的整数倍。


下面来举个例子:


struct A 
{
short a;  4
int b;     4
char c;   4 
double d;    8
};

在GCC下因为系统默认是4字节对齐,所以在我的电脑上运行后结果是20。

由于编译器会优化的问题,各个编译器可能不一样。













原创粉丝点击