文档章节

结构体的内存对齐

大道无名
 大道无名
发布于 2016/10/23 15:12
字数 1703
阅读 17
收藏 0

一、为什么要内存对齐

为了高速处理数据,现代处理器的设计引入了对齐的概念。所谓对齐就是保证数据在内存中存储时地址变化按照一定的规律,这样就可以保证每次cpu取同样长度的数据进行运算,因此可以提高计算机的运行速度。

二、什么是内存对齐

下面的程序演示内存中的对齐:

#include <stdio.h>

struct test{
  char ch;
  short s;
  int i;
};

int main(void)
{
  struct test var;
  printf("size of var : %d\n", sizeof(var));
  return 0;
}

运行结果为:

该结构体拥有一个char型、一个short型和一个int型成员变量,所占用的字节数应该是7个,但是结果却是8个字节,这是因为编译器采用了默认的对齐方式。

三、内存对齐的一些概念

1.数据类型自身的对齐值

基本数据类型的自身对齐值为其数据类型的大小。

2.指定对齐值

默认的指定对齐值为成员中自身对齐值最大的那个值。

使用下面语句可以指定对齐值value:

#progma pack (value) /*指定按value字节对齐*/
struct A {
    int a;
};
#progma pack () /*取消指定对齐,恢复缺省对齐*/

3.结构体或者类的自身对齐值

其成员中自身对齐值最大的那个值。

4.数据类型、结构体和类的有效对齐值

自身对齐值和指定对齐值中较小的那个值。

四、内存对齐的实现

设结构体如下:

struct test{
  char ch;
  int i;
  short s; 
};

假设test的起始地址为0x0000,默认的指定对齐值为4,所以:

  1. 第一个成员变量ch,自身对齐值为1,小于指定对齐值4,所以有效对齐值为1,ch的存放地址为0x0000,并且0x0000是自身对齐值1的倍数。
  2. 第二个成员变量i,自身对齐值是4,等于指定对齐值4,所以有效对齐值为4,而变量起始地址应为自身有效对齐值的倍数,所以i应存放在0x0004到0x0007这四个连续的字节空间。
  3. 第三个成员变量s,自身对齐值为2,小于指定对齐值为4,所以有效对齐值为2,变量起始存放地址应为2的倍数,所以s存放在0x0008到0x0009两个字节空间。
  4. 接下来看结构体test自身对齐值为其变量中最大对齐值(这里是i)所以就是4,所以结构体的有效对齐值也是4,结构体的大小应为结构体有效对齐值的倍数,所以所以0x0000A到0x000B也被结构体所占用,0x0000到0x000B共12个字节,这就是结构体test所占内存大小。

当我们指定对齐值为2字节时,再分析上面的结构体

#pragma pack(2)  //指定按2字节对齐
struct test1{
  char ch;
  int i;
  short s; 
};
#pragma pack()  //取消指定对齐,恢复缺省对齐

 假设test1的起始地址为0x0000,指定对齐值为2,所以:

  1. 第一个成员变量ch,自身对齐值为1,小于指定对齐值为2,所以有效对齐值为1,ch存放在0x0000。
  2. 第二个成员变量i,自身对齐值为4,大于指定对齐值,所以有效对齐值为2,存放的首地址为有效对齐值2的倍数即0x0002,因此i存放在0x0002,0x0003,0x0004,0x0005四个连续的字节空间。
  3. 第三个成员变量s,自身对齐值为2,等于指定对齐值,所以有效对齐值为2,存放首地址为2的倍数即0x0006,因此s存放在0x0006,0x0007两个字节空间。
  4. 结构体test1自身对齐值即最大成员变量自身对齐值4,大于指定对齐值2,所以有效对齐值为2,而结构体大小为0x0000到0x0007共8个字节,是2的倍数,因此结构体test1的内存大小为8字节

五、分析几个程序

1.程序如下:

#include <stdio.h>

#pragma pack(8)
struct example1
{
  short a;
  long b;
};
struct example2
{
  char c;
  struct example1 struct1;
  short e;
};
#pragma pack()

int main(int argc, char* argv[])
{
  struct example2 struct2;
  struct example1 e1;
  printf("size of example1 : %d\n", sizeof(e1));
  printf("size of example2 : %d\n", sizeof(struct2));
  printf("%d\n", (unsigned long int)(&struct2.struct1) - (unsigned long int)(&struct2));

  return 0;
}

程序的输出结果是什么?

答案是:

分析这个程序:

对于example1:

  1. 成员变量a,自身对齐值为2,指定对齐值为8,所以有效对齐值为2,因此a占2个字节空间。
  2. 成员变量b,自身对齐值为8,等于指定对齐值,所以有效对齐值为8,起始地址应为8的倍数,因此需要填充6个字节,b占8个字节空间。
  3. 结构体的有效对齐值为8,而成员变量共占16个字节,是8的倍数,因此结构体example1共占16个字节空间。

对于example2:

  1. 成员变量c,自身对齐值为1,小于指定对齐值,所以有效对齐值为1,占1个字节空间。
  2. 成员struct1是一个example1结构体,该结构体的自身对齐值为8,等于指定对齐值,所以起始地址为8的倍数,因此填充7个字节,占16个字节空间。
  3. 成员e,自身对齐值2,小于指定对齐值,有效对齐值为2,占两个字节大小。
  4. 结构体多有成员所占大小为:1+7+16+2=26,而结构体的有效对齐值为8,因此结构体需占32个字节空间(8的倍数)。 

 对于(unsigned long int)(&struct2.struct1) - (unsigned long int)(&struct2):

因为在example2中struct1之前有个char类型的成员变量,由于struct1的对齐值为8所以char变量需要填充7个字节,因此结果为8。

2.第二个程序:

#include <stdio.h>\

union A
{
  int a[5];
  char b;
  double c;
};

struct B
{
  int n;
  union A a;
  char c[10];
};

int main(void)
{
  union A a1;
  struct B b;
  printf("size of union : %d\n", sizeof(a1));
  printf("size of struct : %d\n", sizeof(b));
  return 0;
}

A和B的大小为:

分析程序:

由于union是共享内存的,首先看每个成员所占大小:

union A
{
  int a[5];  //20字节
  char b;    //1字节
  double c;  //8字节
};

A中各变量默认内存对齐方式,必须以最长的double 8字节对齐,所以A的大小为24字节(20+4)。

结构体B中:

struct B
{
  int n;      //4字节
  union A a;  //24字节
  char c[10]; //10字节
};

由于A是8字节对齐的,所以B中的int与char[]也需要8字节对齐,所以大小为:8+24+16 = 48。

 

© 著作权归作者所有

上一篇: C语言位运算
下一篇: 限定修饰符const
大道无名
粉丝 29
博文 161
码字总数 96019
作品 0
宣城
程序员
私信 提问
C语言:内存地址对齐、大小端详解

阅读(一) 我们常常看到“alignment", "endian"之类的字眼, 但很少有C语言教材提到这些概念. 实际上它们是与处理器与内存接口, 编译器类型密切相关的. 考虑这样一个例子: 两个异构的CPU进行...

follitude
2016/05/10
342
0
由结构体对齐而引发的思考。。。(一)

(由于本文初期在CSDN中编辑的不是太好,现在将其发表于看雪论坛中,具体链接如下: https://bbs.pediy.com/thread-222967.htm ) 从结构体对齐到C++类对象内存模型之一结构体对齐 结构体与类在c...

richard1230
2017/07/29
0
0
从类似微软面试题讲起讲字节对齐

今天需要仔细的总结一下内存对齐机制了,参考了http://www.cnblogs.com/clover-toeic/p/3853132.html的博文。 首先需要牢记对其准则: ①数据类型自身的对齐值,例如char自身对齐值为1字节,...

ShualLiu
2016/12/10
22
0
内存空间对齐

内存空间对其原则: 概念:自身对齐值与有效对齐值。 一般数据成员的自身对齐值为其自生占据的内存空间大小。结构体的自生对齐值为其内部最大数据成员的所占内存空间。 有效对齐值为自身对齐...

allocator
2017/02/23
0
0
结构体字节对齐和网络字节序

前不久,在C++程序中碰到一个有关结构体字节对齐的问题。 一。问题描述 在程序中,定义了一个结构体,如下: typedef struct { char name[33]; int ID; int age; } PERSON; 声明了一个该结构体的...

zhangyujsj
2016/09/13
68
0

没有更多内容

加载失败,请刷新页面

加载更多

Angular 英雄编辑器

应用程序现在有了基本的标题。 接下来你要创建一个新的组件来显示英雄信息并且把这个组件放到应用程序的外壳里去。 创建英雄组件 使用 Angular CLI 创建一个名为 heroes 的新组件。 ng gener...

honeymoose
6分钟前
0
0
Kernel DMA

为什么会有DMA(直接内存访问)?我们知道通常情况下,内存数据跟外设之间的通信是通过cpu来传递的。cpu运行io指令将数据从内存拷贝到外设的io端口,或者从外设的io端口拷贝到内存。由于外设...

yepanl
今天
3
0
hive

一、hive的定义: Hive是一个SQL解析引擎,将SQL语句转译成MR Job,然后再在Hadoop平台上运行,达到快速开发的目的 Hive中的表是纯逻辑表,就只是表的定义,即表的元数据。本质就是Hadoop的目...

霉男纸
今天
3
0
二、Spring Cloud—Eureka(Greenwich.SR1)

注:本系列文章所用工具及版本如下:开发工具(IDEA 2018.3.5),Spring Boot(2.1.3.RELEASE),Spring Cloud(Greenwich.SR1),Maven(3.6.0),JDK(1.8) Eureka: Eureka是Netflix开发...

倪伟伟
昨天
9
0
eclipse常用插件

amaterasUML https://takezoe.github.io/amateras-update-site/ https://github.com/takezoe/amateras-modeler modelGoon https://www.cnblogs.com/aademeng/articles/6890266.html......

大头鬼_yc
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部