C\C++ 内存对齐现象
前几天一个在自学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++ 内存对齐现象的更多相关文章
- 为什么要内存对齐 Data alignment: Straighten up and fly right
转载于http://blog.csdn.net/lgouc/article/details/8235471 为了速度和正确性,请对齐你的数据. 概述:对于所有直接操作内存的程序员来说,数据对齐都是很重 ...
- C/C++的内存对齐
1.内存对齐之pragma pack语法 语法:#pragma pack( [show] | [push | pop] [, identifier], n )作用:指定结构,联合和类的包对齐方式(pa ...
- Sword 计算机内存对齐
内存对齐理论 a.数据的对齐(alignment) 指数据的地址和由硬件条件决定的内存块大小之间的关系.一个变量的地址是它大小的倍数的时候,这就叫做自然对齐(naturally aligned). 例 ...
- C++继承体系中的内存对齐
本篇随笔讨论一个比较冷门的知识,继承结构中内存对齐的问题,如今内存越来越大也越来越便宜,大部分人都已经不再关注内存对齐的问题了.但是作为一个有追求的技术人员,实现功能永远都是最基本的要求,把代码优化到 ...
- struct结构体大小的计算(内存对齐)
本次实验环境 环境1:Win10, QT 5.12 一. 背景 当普通的类型无法满足我们的需求的时候,就需要用到结构体了.结构体可衍生出结构体数组,结构体还可以嵌套结构体,这下子数据类型就丰富多彩了, ...
- 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用
欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...
- C++内存对齐总结
大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...
- C/C++: C++位域和内存对齐问题
1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...
- C/C++ 知识点1:内存对齐
预备知识:基本类型占用字节 在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢? 32位操作系统: char : 1 int :4 short : 2 unsigned ...
随机推荐
- 机器学习基石10-Logistic Regression
注: 文章中所有的图片均来自台湾大学林轩田<机器学习基石>课程. 笔记原作者:红色石头 微信公众号:AI有道 上一节课介绍了Linear Regression线性回归,用均方误差来寻找最佳 ...
- A previous installation of Qt5 Visual Studio Add-in was detected. Please uninstall it before running this installer解决办法
前段时间在安装Qt Visual Studio插件的时候,安装到一半不小心中止了,结果后来怎么安装都不行,提示已经安装了,要先卸载, 可是到哪里都找不到有卸载的,因为压根就没有安装完成.这可害苦我了. ...
- css3兼容360
在头部添加 <!--启用360浏览器的极速模式(webkit) --> <meta name="renderer" content="webkit&qu ...
- 获取clock ticks per second
#include <sys/syscall.h> #include <stdio.h> #include <unistd.h> int main() { print ...
- python url参数转dict
from urllib import parse url='_from=R40&LH_BIN=1&_sop=13&LH_Complete=1&LH_Sold=1& ...
- ansible playbook批量改ssh配置文件,远程用户Permission denied
最近手里的数百台服务器需要改/etc/ssh/sshd_config的参数,禁止root直接登陆,也就是说 [root@t0 ~]# cat /etc/ssh/sshd_config | grep R ...
- maya cmds pymel 选择 uv area(uv 面积) 为0 的面
maya cmds pymel 选择 uv area(uv 面积) 为0 的面 cmds.selectType( pf=True ) cmds.polySelectConstraint( m=3, t ...
- 利用 SQL Server Audit 审核哪些用户添加删除更新SQL Agent Job
有的时候我们需要下放权限给不用的用户,让他们自己能管理一部分SQL Agent Job,此时需要详细记录谁在什么时间修改了Job 甚至删除了Job, 我们可以使用SQL Server 的Audit帮助 ...
- C语言第零次作业
Q1.你对网络专业或者计算机专业了解是怎样? 说实话不了解网络专业,在甚至在填志愿之前我都不曾听说过.但经过一番的查阅资料.现在,首先我了解到我们主要学习计算机.通信以及网络方面的基础理论.设计原理, ...
- native的详细用法
目录 1.JNI:Java Native Interface 3.用C语言编写程序本地方法 一.编写带有 native 声明的方法的java类 二.使用 javac 命令编译所编写的java类,生成. ...