C语言结构体的内存对齐问题
在C语言开发当中会遇到这样的情况:
#include <stdio.h>
struct test {
int a;
char b;
};
int main(int argc, const char * argv[])
{
printf("%lu\n", sizeof(struct test));
return ;
}
sizeof操作输出的结果是8,可是int和char类型的长度加起来只有5,那么为什么输出了8呢?
这就牵扯到结构体的内存对齐问题,事实上,结构体中的变量在内存当中并不是以一种连续紧凑的方式存储的。
上面这个例子是一种最简单的情况,来看一下它的内存排布:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | |
| 0x10 | a | b | 空位 | |||||||||||||
| 0x20 | ||||||||||||||||
可见,从0x15到0x18都是空位,为什么要这样存储呢?因为计算机字长为4,处理结构体变量时,需要一次读入32位,也就是4个字节,那么假定两个结构体变量a和b,a从0x10开始,b从0x15开始的话,则需要两次寻址,第一次是读出0x14到0x17,取出后三位,第二次是从0x18到0x1B,取出第一位,然后做位运算,由于变量处理很频繁,这样就增加了性能的开销,那么只能采取用空间换时间的策略了。
假设有两个结构体变量,那么内存排布是这样的:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | |
| 0x10 | a | b | 空位 | a | b | 空位 | ||||||||||
| 0x20 | ||||||||||||||||
这便是内存对齐的第一个方面——结构体的末尾如果没有对齐,则会留出空位来,为排在它前后的变量提供寻址上的便利。
事实上,结构体的大小,必然是其中占用空间最大的类型的长度的整数倍。
接下来改变一下我们的结构体:
struct test {
char b;
int a;
};
它的长度同样是8,内存排布如下:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | |
| 0x10 | b | 空位 | a | |||||||||||||
| 0x20 | ||||||||||||||||
同样基于上面提到的原因,如果将a放在0x11的位置,需要两次寻址。那么,结构体内存排列的一个重要原则就是要得到最少的寻址次数,显然,为了方便找到int型的a,需要在b后面空出3个字节的空间来。
下面举一个稍微复杂一点的例子:
struct test {
char a;
int b;
char c;
char d;
double e;
char f;
};
它的长度是32,看一下内存排列:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | |
| 0x10 | a | 空位 | b | c | d | 空位 | ||||||||||
| 0x20 | e | f | 空位 | |||||||||||||
为了让变量b寻址方便,在a的后面空出了3个字节,而c和d无论如何都要寻址一次,所以顺序排下去就可以了,而e长度为8,按说可以从0x1C开始排,但是这里需要和类型本身的长度8进行对齐,则排在了0x20的位置,于是乎d的后面又空出了6个字节的空间,最后f排在e的后面,之后为了结构体本身和最长类型的长度8对齐,后面又留出了7个字节的空位。
显而易见结构体当中变量的顺序是会影响存储空间的,在设计结构体的时候需要进行优化,比如将上面的结构体改写成下面的形式可以节省空间:
struct test {
char a;
char c;
char d;
char f;
int b;
double e;
};
这种排列只占用16字节,内存如下:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | |
| 0x10 | a | c | d | f | b | e | ||||||||||
| 0x20 | ||||||||||||||||
可见,内存对齐是一种空间换时间的手段,当然,为了节约内存,可以通过如下代码令结构体紧凑排列:
#pragma pack(1)
C语言结构体的内存对齐问题的更多相关文章
- C语言 结构体的内存对齐问题与位域
http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...
- 3.c语言结构体成员内存对齐详解
一.关键一点 最关键的一点:结构体在内存中是一个矩形,而不是一个不规则形状 二.编程实战 #include <stdlib.h> #include <stdio.h> stru ...
- C语言结构体在内存中的存储情况探究------内存对齐
条件(先看一下各个基本类型都占几个字节): void size_(){ printf("char类型:%d\n", sizeof(char)); printf("int类 ...
- C语言结构体及其内存布局
code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); ...
- C语言结构体的字节对齐原则
为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...
- C语言结构体变量字节对齐问题总结
结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...
- C语言结构体占用空间内存大小解析
结构体的数据类型的有点我们就不啰嗦了,直接来看相同数据结构体的几种书写的格式吧. 格式一: 01.struct tagPhone 02.{ 03. char A; 04. int ...
- c语言结构体在内存中存储,字节对齐
注意: 出于效率的考虑,C语言引入了字节对齐机制,一般来说,不同的编译器字节对齐机制有所不同,但还是有以下3条通用准则: (1)结构体变量的大小能够被其最宽基本类型成员的大小所整除: (2)结构体每个 ...
- C语言结构体变量内存分配与地址对齐
地址对齐简单来说就是为了提高访问内存的速度. 数组的地址分配比较简单,由于数据类型相同,地址对齐是一件自然而然的事情. 结构体由于存在不同基本数据类型的组合,所以地址对齐存在不同情况,但总体来说有以下 ...
随机推荐
- 单源最短路径—Bellman-Ford和Dijkstra算法
Bellman-Ford算法:通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重相同时为止.该算法主要是基于下面的定理: 设G=(V,E) ...
- Hive 12、Hive优化
要点:优化时,把hive sql当做map reduce程序来读,会有意想不到的惊喜. 理解hadoop的核心能力,是hive优化的根本. 长期观察hadoop处理数据的过程,有几个显著的特征: 1. ...
- hdu 4336 Card Collector(期望 dp 状态压缩)
Problem Description In your childhood, people in the famous novel Water Margin, you will win an amaz ...
- mysql-error --(ERROR 1135 (HY000): Can't create a new thread (errno 11); if you are not out)
报错信息: ERROR 1135 (HY000): Can't create a new thread (errno 11); if you are not out 解决办法: # 查看限制情况 [r ...
- [Javascript] How to write a Javascript libarary
Create package.json file //npm settings npm set init-author-name 'username' npm set init-author-emai ...
- Rhythmbox乱码的解决的方法
近期尝试 Listen 和 Banshee 才发现,Rhythmbox 上出现的 mp3乱码问题依然,并且更加严重,想要彻底弄清和解决必须搞清两点,第一, mp3 标签类型和编码,第二,各种播放器对 ...
- UIProgressView-初识IOS
好几天没更新了,学的时候太紧,没时间复习了都.今天刚好有时间,多更几个. 今天复习的是UIProgressView,我们常见使用在修改某些属性的时候经常用到,比如透明度,今天我们介绍一个简单的使用例子 ...
- WEB服务器3--IIS7.0安装和配置
安装Web服务器(IIS) 点击开始菜单->所有程序->管理工具->服务器管理器,启动服务器管理器,界面如下: 在服务器管理器中,选择角色,你将可以看到角色总视图. 点击添加角色,会 ...
- MySql命令——show,分页,正则表达式
先要安装MySql,过程见 MySql5.1在Win7下的安装与重装问题的解决 不是教程,还没有写教程的资格,只是为了自己查阅而已! show show databases; //显示所有数据库 ...
- SQL Server无法打开用户默认数据库,登录失败,用户‘sa’登录失败,错误:4064的解决方法
用windows验证方式进入Management Studio, 安全性 > 用户名 > 右击sa > 属性 > 把默认数据库选“master”