zoukankan      html  css  js  c++  java
  • 结构体内存分配问题

    引入

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

    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整除。

  • 相关阅读:
    江西师范大学瑶湖校区图片
    什么是sp?
    教育技术学硕士点学校排名
    西南师大教育技术学专业2005年入学考试信息
    什么是"工包"?
    买书网址
    2006年全国教育技术学专业新增硕士点
    今天终于拿到书了
    2007年教育学专业基础综合考试大纲(重要部分) ——下载地址
    电脑DIY推荐
  • 原文地址:https://www.cnblogs.com/yunlambert/p/9589574.html
Copyright © 2011-2022 走看看