博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
结构体内存分配问题
阅读量:4565 次
发布时间:2019-06-08

本文共 1452 字,大约阅读时间需要 4 分钟。

引入

最近上课的时候老师问我们下面这段代码:

struct test {    char a=1;    short l=2;};

中a和l在内存中占几个字节,它们的排列方式是连续在一起的还是分开的? 占多少字节如果是内存对齐的话会是4字节、设置#pragma pack(1)的话则是3字节;但是他们的排列方式还真的不清楚,所以今天研究一下。

解答

首先我们先回答问题,再介绍一下原理,先写个程序看一下:

struct test {    char a=1;    short l=2;};int main(){    test A;    auto address_a = &(A.a);    auto address_l = &(A.l);}

查看一下地址,进而查阅内存:

02.PNG
01.PNG
内存分布为0x0018FC5C-0x0018FC5F:01 cc 02 00
所以是间隔分布的,但如果我们加上#pragma pack(1):

#pragma pack(1)struct test {    char a=1;    short l=2;};#pragma pack()int main(){    test A;    auto address_a = &(A.a);    auto address_l = &(A.l);}

则内存分布为:

03.PNG
变成了01 02 00 cc,符合我之前的结论。

原理

结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节;

char a;short i;

如果a的地址是0x0000,那么i的地址将会是0x0002或者是0x0004。那么就出现这样一个问题:0x0001这个地址没有被使用;它确实没被使用。因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。如果变量i的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入i的低8位,然后再从0x0002中读取下一个short,取它的低8位放入i的高8位中,这样的话,为了获得i的值,CPU需要进行了两次读操作。

但是如果i的地址为0x0002,那么CPU只需一次读操作就可以获得i的值了。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐(对变量i做内存对齐,a、i之间的内存被浪费,a并未多占内存)。
结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:
(1)每个成员分别按自己的对齐字节数和PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。
(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。
(3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。
(4)计算结构体的内存大小时,应该列出每个成员的偏移地址,则其长度=最后一个成员的偏移地址+最后一个成员数的长度+最后一个成员的调整参数(考虑PPB)。
注意:
(1)字节对齐取决于编译器;
(2)一定要注意PPB大小,PPB大小由pragam pack(n)指定;
(3)结构体占用的字节数要能被PPB整除。

转载于:https://www.cnblogs.com/yunlambert/p/9589574.html

你可能感兴趣的文章
窗口 对话框 Pop Dialog 示例
查看>>
ubuntu(centos) server安装vmware tools
查看>>
数据结构之最大不重复串
查看>>
为什么要配置sdk-tools/platform-toools?
查看>>
自己动手开发更好用的markdown编辑器-07(扩展语法)
查看>>
maven dependency:tree中反斜杠的含义
查看>>
队列的循环队列
查看>>
程序中的日期格式
查看>>
大众点评CAT错误总结以及解决思路
查看>>
MyEclipse 检出新项目后,如果项目名称签名有个红色感叹号
查看>>
Java开发环境系列:一篇能解决你99%问题的排雷日记
查看>>
从0开始学爬虫3之xpath的介绍和使用
查看>>
Shell成长之路
查看>>
vim下正则表达式的非贪婪匹配
查看>>
一个python的计算熵(entropy)的函数
查看>>
spring源码学习——spring整体架构和设计理念
查看>>
模拟window系统的“回收站”
查看>>
OpenCV中的split函数
查看>>
MongoDB divide 使用之mongotempalte divide
查看>>
SSH不允许进行DNS解析
查看>>