前几天一个在自学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. luogu P5305 [GXOI/GZOI2019]旧词

    传送门 先考虑\(k=1\),一个点的深度就是到根节点的路径上的点的个数,所以\(lca(x,y)\)的深度就是\(x\)和\(y\)到根路径的交集路径上的点的个数,那么对于一个询问,我们可以对每个点 ...

  2. Ubuntu 18.04 记录

    登录后死机,关机时死机的解决方法 更新内核并安装 Nvidia 显卡驱动可解决. 在内核更新为 4.15.18,Nvidia 显卡驱动为 390 时,问题解决. 使用 LiveCD 启动,然后 mou ...

  3. 数据库运维平台~Yearning测试与总结

    一 部署   1 docker-compose up -d 即可非常方便   2 mysql安装   3 inception安装二 默认账号   默认用户admin 密码: Yearning_admi ...

  4. Q - N! HDU - 1042

    使用java还不熟练,错误在于读入.应用in.hasNext() 代码 import java.text.ParseException; import java.text.SimpleDateForm ...

  5. Cyclone IV FPGA 器件笔记

    LE(逻辑单元)操作模式 1) 正常模式 2)算术模式 可以看到对于Cy4来说正常模式和算术模式的区别就是正常模式有一个4输入LUT没有cout进位输出,而算术模式有两个3输入LUT有cout进位输出 ...

  6. maven的配置-2019-4-13

    一.Maven的优点 1.  依赖管理 jar 包管理 2.一键构建 (编译-----测试------打包-----安装-----部署 ) 什么是项目构建? 指的是项目从编译-----测试------ ...

  7. D - WE POJ - 3273 (二分法)

    Farmer John is an astounding accounting wizard and has realized he might run out of money to run the ...

  8. TopN案例

    准备三份数据 t1 2067 t2 2055 t3 2055 t4 1200 t5 2367 t6 255 t7 2555 t8 12100 t9 20647 t10 245 t11 205 t12 ...

  9. vue computed、methods、watch的区别

    1.computed(计算属性)computed是计算属性,事实上和和data对象里的数据属性是同一类的(使用上), 2.methods(方法)写在html中的时候需要带()支持传参,且需要有触发条件 ...

  10. GIT----IDEA配置git

    配置git 创建本地厂库 可以选中项目所在的目录下 此时发现所有的页面的文件都变红,是因为变红的文件还没有add 添加提交的项目(add) 选中提交的文件右击,git ,add 如果想把整个项目都ad ...