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 ...
随机推荐
- nginx反向代理配置两个不同服务器
1.什么是反向代理通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中由代理服务器向Inter ...
- 深度学习之自编码器AutoEncoder
原文地址:https://blog.csdn.net/marsjhao/article/details/73480859 一.什么是自编码器(Autoencoder) 自动编码器是一种数据的压缩算法, ...
- CodeForces 671C - Ultimate Weirdness of an Array
题意: 给以一个定义, F(l, r) 的值表示序列 A[1:n]的子序列 A[1....(l-1),(r+1)...n] 之中 任意两个数的最大公约数的最大值. 求 Sum=∑i=1N∑j=1N(F ...
- 【原创】大叔经验分享(47)yarn开启日志归集
yarn开启日志归集功能,除了配置之外 yarn.log-aggregation-enable=true 还要检查/tmp/logs目录是否存在以及权限,尤其是在开启kerberos之后,有些目录可能 ...
- c博客作业--分支、顺序结构
1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量学习体会 1.2.1学习体会 对于本章学习我感觉对代码有了初步的了解,一些简单的题目可以熟练掌握,但现在解决一道题目花的时间过多,不易发现那 ...
- angular/cli 常用指令
1.安装@angular/cli npm install -g @angular/cli 2.更新@angular/cli npm uninstall -g @angular/cli npm cach ...
- ***新版微信H5支付技术总结(原创)
新版微信H5支付官方文档: https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1 H5支付是指商户在微信客户端外 ...
- Net Core Docker 容器部署,修改,保存
运行镜像 [root@localhost opt]# docker run -itd -p : microsoft/dotnet:latest 查看运行的docker [root@localhost ...
- Linux网络技术管理及进程管理
OSI七层模型和TCP/IP四层模型 OSI七层模型:OSI(Open System Interconnection)开放系统互连参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联 ...
- Netty5服务端源码解析
Netty5源码解析 今天让我来总结下netty5的服务端代码. 服务端(ServerBootstrap) 示例代码如下: import io.netty.bootstrap.ServerBootst ...