前几天一个在自学C语言的小伙伴问了我个问题,C语言结构体储存所占空间为啥和自己预测的不一样。看一下下面这一段代码:

struct node{
int num;
char ch;
}a;
printf("%d",sizeof(a));

  在我们主动去申请内存的角度看来,申请一个上面的结构体,sizeof( int ) = 4; sizeof( char ) =1; sizeof( node ) 应该等于5才对,但是程序运行得出的却是8。

  小伙伴对于这个结果很是不解。这其实是C\C++ 储存规则中的内存对齐(字节对齐)原则。

一 什么是字节对齐
  现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

二 对齐的原因和作用
  不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种架构下编程必须保证字节对齐。

  但最常见的情况是,如果不按照平台要求对数据存放进行对齐,会带来存取效率上的损失。比如32位的Intel处理器通过总线访问(包括读和写)内存数据。每个总线周期从偶地址开始访问32位内存数据,内存数据以字节为单位存放。如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。

  因此,通过合理的内存对齐可以提高访问效率。为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址能够被4整除。

  单纯的文字说明还是没那么好理解,下面我将通过几程序来让我们更清楚的了解到什么是内存对齐。ps: int的内存大小会随着操作系统的位数发生变化

#include "stdio.h"
struct node1 {
char a;char b;
};
struct node2 {
short a;char b;
};
struct node3 {
int a;char b;
};
struct node4 {
long a;char b;
};
struct node5 {
double a;char b;
};
int main() {
node1 char_char;
node2 short_char;
node3 int_char;
node4 long_char;
node5 double_char;               //程序输出:
printf("%d\n",sizeof(char_char));      // 2
printf("%d\n",sizeof(short_char));      // 4
printf("%d\n",sizeof(int_char));    // 8
printf("%d\n",sizeof(long_char));      // 8
printf("%d\n",sizeof(double_char));     // 16
return ;
}

  从上面这段代码及其输出结果,我们能够较为清晰的看到每个结构体的所占空间大小,均为其占内存较大的单位变量大小的倍数。

  然后考虑到如果我们需要在一个结构体内存很多个不同单位的变量时候是怎么存的呢?

#include "stdio.h"
struct node{
char ch; char ch1;
short st; char ch2;
int it; char ch3;
double db;char ch4;
}nd;
int main(){ //程序输出:
printf("%d",sizeof(nd)); //32
return ;
}

  这下又让人迷惑了,虽然确实是 较大内存的double类型的整数倍 3*8 但是具体怎么储存的呢,我们输出一下这个结构体每个子成员的地址。

    printf("&ch=0x%X   &ch1=0x%X   &st=0x%X   &ch2=0x%X \n",&nd.ch,&nd.ch1,&nd.st,&nd.ch2);
printf("&it=0x%X &ch3=0x%X &db=0x%X &ch4=0x%X \n",&nd.it,&nd.ch3,&nd.db,&nd.ch4);

这样有点抽象,不妨画个图:

可以很明显看到,图表中的所有地址就是整个结构体占用的所有空间。 内存申请空间以double对齐。交换一下结构体的声明顺序:

struct node{
char ch; char ch1;
int it; char ch3;
short st; char ch2;
char ch4; double db;
}nd;

  这下算比较清晰了,int类型以四个字节进行对齐,short类型以两个字节进行对齐,char类型在对齐规则下进行单字节填充。

  所以可以看到在定义结构体的时候进行适当的元素顺序调整可以有效的节省内存空间。

  包含字符串的结构体也是如此:

  

当然我们也可以通过 #pragma pack(n) 来改变这个内存对齐的方式:

#include "stdio.h"
#pragma pack(1)//设定为 1 字节对齐
double a;
struct node{
char ch; char ch1;
int it; char ch3;
short st; char ch2;
char ch4; double db;
}nd;
int main(){
printf("%d\n",sizeof(nd));
printf("&ch=0x%X &ch1=0x%X &st=0x%X &ch2=0x%X \n",&nd.ch,&nd.ch1,&nd.st,&nd.ch2);
printf("&it=0x%X &ch3=0x%X &db=0x%X &ch4=0x%X \n",&nd.it,&nd.ch3,&nd.db,&nd.ch4);
return ;
}

内存对齐调整前

内存对齐调整后

调整内存就会出现前面文本所说处理器访问效率变低的问题。

C\C++ 内存对齐现象的更多相关文章

  1. 为什么要内存对齐 Data alignment: Straighten up and fly right

    转载于http://blog.csdn.net/lgouc/article/details/8235471 为了速度和正确性,请对齐你的数据. 概述:对于所有直接操作内存的程序员来说,数据对齐都是很重 ...

  2. C/C++的内存对齐

    1.内存对齐之pragma pack语法 语法:#pragma pack( [show] | [push | pop] [, identifier], n )作用:指定结构,联合和类的包对齐方式(pa ...

  3. Sword 计算机内存对齐

    内存对齐理论 a.数据的对齐(alignment) 指数据的地址和由硬件条件决定的内存块大小之间的关系.一个变量的地址是它大小的倍数的时候,这就叫做自然对齐(naturally aligned). 例 ...

  4. C++继承体系中的内存对齐

    本篇随笔讨论一个比较冷门的知识,继承结构中内存对齐的问题,如今内存越来越大也越来越便宜,大部分人都已经不再关注内存对齐的问题了.但是作为一个有追求的技术人员,实现功能永远都是最基本的要求,把代码优化到 ...

  5. struct结构体大小的计算(内存对齐)

    本次实验环境 环境1:Win10, QT 5.12 一. 背景 当普通的类型无法满足我们的需求的时候,就需要用到结构体了.结构体可衍生出结构体数组,结构体还可以嵌套结构体,这下子数据类型就丰富多彩了, ...

  6. 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用

    欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...

  7. C++内存对齐总结

    大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...

  8. C/C++: C++位域和内存对齐问题

    1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...

  9. C/C++ 知识点1:内存对齐

    预备知识:基本类型占用字节 在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢? 32位操作系统: char : 1    int :4    short : 2    unsigned ...

随机推荐

  1. pythonのdjango 缓存

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...

  2. P5303 [GXOI/GZOI2019]逼死强迫症

    题目地址:P5303 [GXOI/GZOI2019]逼死强迫症 这里是官方题解 初步分析 从题目和数据范围很容易看出来这是一个递推 + 矩阵快速幂,那么主要问题在于递推的过程. 满足条件的答案一定是以 ...

  3. nginx conf_ctx ****

    http://blog.chinaunix.net/uid-27767798-id-3840094.html 断断续续看完了,还是没有全部清晰

  4. Django-ORM-单表操作

    ORM字段参数及单表操作 一.字段参数 1.字段 AutoField(Field) #当model中如果没有自增列,则会自动创建一个列名为id的列 -int 自增列,必须填入参数primary_key ...

  5. 使用element-ui遇到的各种小问题

    一.Dialog对话框 1.在使用嵌套Dialog的时候,会出现遮罩层在内容的上方这种错乱情况 解决办法:http://element-cn.eleme.io/#/zh-CN/component/di ...

  6. 最优的路线(floyd最小环)

    问题描述 学校里面有N个景点.两个景点之间可能直接有道路相连,用Dist[I,J]表示它的长度:否则它们之间没有直接的道路相连.这里所说的道路是没有规定方向的,也就是说,如果从I到J有直接的道路,那么 ...

  7. xpath定位动态iframe

    使用xpath定位 driver.switch_to.frame(driver.find_element_by_xpath("//iframe[starts-with(@id, 'x-URS ...

  8. 主席树——求区间第k个不同的数字(向右密集hdu5919)

    和向左密集比起来向右密集只需要进行小小的额修改,就是更新的时候从右往左更新.. 自己写的被卡死时间.不知道怎么回事,和网上博客的没啥区别.. /* 给定一个n个数的序列a 每次询问区间[l,r],求出 ...

  9. 主席树——求区间[l,r]不同数字个数的模板(向左密集 D-query)

    主席树的另一种用途,,(还有一种是求区间第k大,区间<=k的个数) 事实上:每个版本的主席树维护了每个值最后出现的位置 这种主席树不是以权值线段树为基础,而是以普通的线段树为下标的 /* 无修改 ...

  10. Hanlp学习笔记

    一.首先要引入mawen依赖包: <dependency> <groupId>com.hankcs</groupId> <artifactId>hanl ...