精华内容
下载资源
问答
  • 主要给大家总结了关于C++面试题中结构体内存对齐计算问题的相关资料,文中通过示例代码介绍的非常详细,通过这些介绍的内容对大家在面试C++工作的时候,会有一定的参考帮助,需要的朋友们下面随着小编来一起学习学习...
  • 结构体内存对齐

    2021-01-19 11:36:29
    C++学习笔记:结构体内存对齐1.什么是结构体内存对齐2.结构体为何要对齐访问3.结构体对齐的规则和运算4.#pragma pack(n)对齐指令5.__attribute__()对齐指令 1.什么是结构体内存对齐 来看这样一种现象: #include<...

    1.什么是结构体内存对齐

    来看这样一种现象:

    #include<stdio.h>
    #include<stdlib.h>
    
    typedef struct student{	//定义结构体类型
    	char a;
    	int age;
    }stu;//stu是新的类型名 而不是一个变量
    
    int main(int argc,char**argv)
    {
    	printf("sizeof char = %d.\nsizeof int = %d.\nsizeof stu = %d.\n",
    			sizeof(char),sizeof(int),sizeof(stu));
    	return 0;
    }
    

    输出:

    sizeof char = 1.
    sizeof int = 4.
    sizeof stu = 8.
    

    为什么char是1个字节,int是4个字节,但是结构体却占了8个字节?

    结构体中元素的访问本质上是用指针结合这个元素在整个结构体中的偏移量和这个元素的类型来进行访问的。

    但是实际上结构体的元素的偏移量还要复杂,因为结构体要考虑元素的对齐访问,所以每个元素时间占的字节数和自己本身的类型所占的字节数不一定完全一样。比如char实际占字节数可能是1,也可以是2,也可能是3,也可以能4。

    一般来说,当我们用.的方式来访问结构体元素时是不用考虑结构体的元素对齐的,因为编译器会帮我们处理这个细节。但是因为C/C++语言本身是很底层的语言,做嵌入式开发时经常需要从内存角度,以指针方式来处理结构体及其中的元素,因此还是需要掌握结构体对齐规则。

    2.结构体为何要对齐访问

    结构体中元素对齐访问主要原因是为了配合硬件,也就是说硬件本身有物理上的限制,如果对齐排布和访问会提高效率,否则会大大降低效率。

    例如对于一个64位的机器,在一个存取周期Tm内可以取出一行64位数据,假设有这样一批数据,它们的大小分别为8位,16位,32位,64位,来看下面几种在主存中数据存放的方法:


    1.不浪费存储空间的方法:
    首先存8位的数据,然后存16位的数据,当接下来存64位的数据时,一行只剩40位空间了,所以分成前40位和后24位存到两行里,这样的好处是不浪费存储空间,坏处就是当需要取出那个64位数据的时候,需要进行两次访存才可全部取出来,因为一次只能取出一行数据,牺牲了时间换取了空间。
    在这里插入图片描述
    ps:这里绘图的时候写错了,应该是后24位。


    2.从存储字起始位置开始放

    来了一个8位数据就存放在第一个存储字里,剩下的56位就浪费了,来了一个16位的数据就放在第二哥存储字里,剩下的48位就浪费了。。。这样就可以保证所有的数据都可以在一个Tm内取出来,这样处理的缺点很明显,太浪费空间了,牺牲空间换取了时间。
    在这里插入图片描述


    3.边界对齐的数据存放方法
    边界对齐的数据存放方法是上面2种方法的折中,存的下的时候就存,当某个数据一行内存不下的时候就另起一行。
    在这里插入图片描述


    内存本身是一个物理器件(DDR内存芯片,SoC上的DDR控制器),本身有一定的局限性:对于32位的机器来说,如果内存每次访问时按照4字节对齐访问,那么平均下来效率是最高的;如果不对齐访问效率要低很多。还有很多别的因素和原因导致需要对齐访问,比如Cache的一些缓存特性,还有其他硬件(如MMU、LCD显示器)的一些内存依赖特性,所以会要求内存对齐访问。

    3.结构体对齐的规则和运算

    编译器本身可以设置内存对齐的规则,有以下的规则:

    • 1.当编译器设置为4字节对齐时,结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数(如果编译器设置为8字节对齐,则这里的4都要改成8)。
    • 2.结构体中每个元素本身都必须对齐存放,而每个元素本身都有自己的对齐规则。

    编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。

    #include<stdio.h>
    #include<stdlib.h>
    
    typedef struct student{	//定义结构体类型
    	char a;
    	int age;
    }stu;//stu是新的类型名 而不是一个变量
    
    int main(int argc,char**argv)
    {
    	printf("sizeof char = %d.\nsizeof int = %d.\nsizeof stu = %d.\n",
    			sizeof(char),sizeof(int),sizeof(stu));
    	return 0;
    }
    

    4.#pragma pack(n)对齐指令

    #pragma是用来设置编译器的对齐方式的。在32位机器中,编译器的默认对齐方式是4,但是有时候我们不希望对齐方式是4而希望是别的,比如希望1字节对齐,也可能希望是8,甚至可能希望128字节对齐。

    使用方法是以#prgama pack(n)开头,以#pragma pack()结尾定义一个区间,则这个区间内的时n字节对齐。举个栗子:

    #include<stdio.h>
    
    #pragma pack(1)
    //#pragma pack(4)
    typedef struct student{	//定义结构体类型
    	char b;
    	int a;
    	short c;
    }stu;//stu是新的类型名 而不是一个变量
    #pragma pack()
    
    int main(int argc,char**argv)
    {
    	printf("sizeof char = %d.\nsizeof int = %d.\nsizeof short = %d.\nsizeof stu = %d.\n",
    		sizeof(char),sizeof(int),sizeof(short),sizeof(stu));
    
    	return 0;
    }
    

    n=1时输出:

    sizeof char = 1.
    sizeof int = 4.
    sizeof short = 2.
    sizeof stu = 7.
    

    n=4时输出:

    sizeof char = 1.
    sizeof int = 4.
    sizeof short = 2.
    sizeof stu = 12.
    

    #prgma pack的方式在很多C环境下都是支持的,gcc也支持但是不建议使用。

    5.attribute()对齐指令

    __attribute__((packed))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。packed的作用就是取消对齐访问,结果同于#pragma pack(1)。举个栗子:

    #include<stdio.h>
    
    struct student{	//定义结构体类型
    	char b;
    	int a;
    	short c;
    }__attribute__((packed));
    
    int main(int argc,char**argv)
    {
    	printf("sizeof char = %d.\nsizeof int = %d.\nsizeof short = %d.\nsizeof struct student = %d.\n",
    		sizeof(char),sizeof(int),sizeof(short),sizeof(struct student));
    
    	return 0;
    }
    

    输出:

    sizeof char = 1.
    sizeof int = 4.
    sizeof short = 2.
    sizeof struct student = 7.
    

    __attribute__((aligned(n)))使用时也是直接放在要进行内存对齐的类型定义的后面,它起作用的范围只有加了这个东西的这一个类型。它的作用是让整个结构体变量整体进行n字节对齐,注意是结构体变量整体n字节对齐,而不是结构体内各元素也要n字节对齐。

    #include<stdio.h>
    
    typedef struct student{	//定义结构体类型
    	char b;
    	int a;
    	short c;
    }stu __attribute__((aligned(4)));
    
    int main(int argc,char**argv)
    {
    	printf("sizeof char = %d.\nsizeof int = %d.\nsizeof short = %d.\nsizeof struct student = %d.\n",
    		sizeof(char),sizeof(int),sizeof(short),sizeof(stu));
    
    	return 0;
    }
    

    输出:

    sizeof char = 1.
    sizeof int = 4.
    sizeof short = 2.
    sizeof struct student = 12.
    

    注意:__attribute__((aligned(n)))是整体对齐,#prgama pack(n)是内部元素和整体都对齐。往大去对齐2种方式都可以用,但是往小去对齐时,前者失效,后者有用。

    展开全文
  • 结构体内存对齐规则: 1.第一个成员在结构体变量偏移量为0 的地址处。 2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux...

    结构体内存对齐规则:
    1.第一个成员在结构体变量偏移量为0 的地址处。
    2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux默认值为4(也有说法说linux中没有默认).
    3.结构体总大小为最大对齐数的整数倍。(每个成员变量都有自己的对齐数)
    4.如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。

    struct S3 {
    	double d;
    	char c;
    	int i;
    
    };
    
    struct S4 {
    	int f;
    	char c;
    	struct S3 s3;
    
    
    };
    int main() {
    	//struct S3 s3 = {20.1,'a',4};
    	//struct S4 s4 = { 'b',s3,0xffffffff };
    
    	struct S3 s3 ;
    	struct S4 s4 ;
    
    	printf("%d\n", sizeof(s4));
    
    	return 0;
    }
    

    这里已知s3是16字节
    以上s4的大小是24,首先int类型4个字节;char类型1个字节;s3是16个字节与vs编译器8相比较大,s3的最大对齐数就是8而不是16(第二条);这样就从偏移量8的位置开始添加,前面空余3个字节,这样总字节数为4+1+3+16=24,而最大的对齐数为s3的对齐数8,24也是8的整数倍(第三条第四条)。输出24、

    struct S3 {
    	double d;
    	char c;
    	int i;
    
    };
    
    struct S4 {
    
    	char c;
    	struct S3 s3;
    	int f;
    
    };
    int main() {
    	//struct S3 s3 = {20.1,'a',4};
    	//struct S4 s4 = { 'b',s3,0xffffffff };
    
    	struct S3 s3 ;
    	struct S4 s4 ;
    
    	printf("%d\n", sizeof(s4));
    
    	return 0;
    }
    

    上方代码与前文代码在S4中int f的位置发生了变化。故及算法方式为1+7+16+4=28。而最大的对齐数为8(s3的),而28不是8的倍数。距离最近的8的倍数是32.故此结果是32。

    展开全文
  • 结构体内存对齐(如何计算结构体的大小)

    千次阅读 多人点赞 2021-03-03 20:04:07
    文章目录结构体内存对齐规则结构体大小计算 - 三步曲为什么存在内存对齐?设计结构体时的技巧修改默认对齐数 结构体内存对齐规则 我们知道,整型变量有自己的大小,浮点型变量有自己的大小,数组也有自己的大小,...

    结构体内存对齐规则

    我们知道,整型变量有自己的大小,浮点型变量有自己的大小,数组也有自己的大小,那么结构体有没有自己的大小呢?
    回答是肯定的,结构体也有自己的大小,但是结构体的大小并不是简单地将每个结构体成员的大小相加就能得到。

    结构体的大小计算遵循结构体的对齐规则

    1. 第一个成员在与结构体变量偏移量为0的地址处。(即结构体的首地址处,即对齐到0处)
    2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
    4. 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

    对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。
    注:VS中的默认对齐数为8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。

    结构体大小计算 - 三步曲

    知道了结构体内存对齐规则,我们就可以计算结构体的大小了。计算结构体的大小可分为三个步骤。我们拿下面这个结构体举例:

    struct S
    {
    	double d;
    	char c;
    	int i;
    };
    

    第一步:找出每个成员变量的大小将其与编译器的默认对齐数相比较,取其较小值为该成员变量的对齐数。
    在这里插入图片描述
    注:我使用的是VS编译器,故默认对齐数为8。

    第二步:根据每个成员对应的对齐数画出它们在内存中的相对位置。
    在这里插入图片描述

    第三步:通过最大对齐数决定最终该结构体的大小。

    通过图我们可以知道,绿色部分(double d成员占用)+红色部分(char c成员占用)+紫色部分(int i成员占用)+红色与紫色之间的白色部分(浪费掉了)总共占用了16个字节的内存空间。
    我们需要将它们总共占用的内存空间(16)与结构体成员的最大对齐数(8)相比较,结构体的总大小为最大对齐数的整数倍,此时16正好是8的整数倍,所以该结构体在VS编译器下的大小就16个字节。即创建一个该类型的结构体变量,内存需为其开辟16个字节的内存空间。

    注意:大多数情况下,成员变量已经占用的总字节个数并不一定正好为其成员变量中的最大对齐数的整数倍,这时我们需要将其扩大为最大对齐数的整数倍。

    为什么存在内存对齐?

    平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常。
    比如,当一个平台要取一个整型数据时只能在地址为4的倍数的位置取得,那么这时就需要内存对齐,否则无法访问到该整型数据。

    性能原因: 数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次。

    在画图时可能有博友会想,内存这么重要,在进行内存对齐的时候怎么还有内存被白白浪费掉呢?
    现在看来,其实结构体的内存对齐是拿空间来换取时间的做法。

    设计结构体时的技巧

    其实在我们设计结构体的时候,如果结构体成员的顺序设计得合理的话,是可以避免不必要的内存消耗的。
    两个结构体的成员变量相同,但是成员变量的顺序不同,可能就会出现结构体的大小不同的情况:

    struct S1
    {
    	char a;
    	char b;
    	int c;
    };//结构体1
    struct S2
    {
    	char a;
    	int c;
    	char b;
    };//结构体2
    

    我们可以看到,结构体1和结构体2的成员变量一模一样,可是当我们按照内存对齐规则来计算两个结构体的大小的时候,会发现两个结构体的大小不一样,在VS编译器下第一个结构体大小为8,第二个结构体大小为12。

    可以见得,结构体成员变量的顺序不同,可能会造成内存不必要的损失。将占用空间小的成员尽量集中在一起,可以有效地避免内存不必要的浪费。

    修改默认对齐数

    要修改编译器的默认对齐数,我们需要借助于以下预处理命令:

    #pragma pack()
    

    如果在该预处理命令的括号内填上数字,那么默认对齐数将会被改为对应数字;如果只使用该预处理命令,不在括号内填写数字,那么会恢复为编译器默认的对齐数。

    #include <stdio.h>
    
    #pragma pack(4)//设置默认对齐数为4
    struct S1
    {
    	char a;//1/4->1
    	int b;//4/4->4
    	char c;//1/4->1
    };//12
    #pragma pack()//取消设置的默认对齐数,还原为默认
    
    #pragma pack(1)//设置默认对齐数为1
    struct S2
    {
    	char a;//1/1->1
    	int b;//4/1->1
    	char c;//1/1->1
    };//6
    #pragma pack()//取消设置的默认对齐数,还原为默认
    
    int main()
    {
    	printf("%d\n", sizeof(struct S1));//打印结果为12
    	printf("%d\n", sizeof(struct S2));//打印结果为6
    	return 0;
    }
    

    于是,当结构体的对齐方式不合适的时候,我们可以自己更改默认对齐数。

    展开全文
  • 总结:结构体内存对齐就是拿空间换时间的做法 平台原因(移植原因):某些硬件平台只能在某些地址处取某些特定类型的数据 否则抛出硬件异常 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐为了访问未

    内存对齐的意义

    为什么要内存对齐:

    • 内存的最小单元是一个字节;CPU实际上将内存当成多个块,每次从内存中读取一个块,这个块的大小可能是2、4、8、16等。
    • 如果没有对齐,为了访问一个变量可能产生二次访问;有了内存对齐,可以提高操作系统访问内存的效率。

    我们来分析下非内存对齐和内存对齐的优缺点在哪?
    在这里插入图片描述

    总结:结构体的内存对齐就是拿空间换时间的做法

    • 平台原因(移植原因):某些硬件平台只能在某些地址处取某些特定类型的数据 否则抛出硬件异常
    • 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐为了访问未对齐的内存 处理器需要作两次内存访问而对齐的内存仅需要一次访问

    内存对齐的规则

    1第一个成员变量在结构体变量偏移量为0的地址处;
    2第二个属成员变量开始,放在 min(该类型的大小 ,对齐模数) 的整数倍上
    3整体计算完毕后算总大小,结构体总大小必须是 min(该结构体中最大数据类型 ,对齐模数) 整数倍,如果不是应当补齐;如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐模数的整数倍处;

    • 设置默认对齐数为8:# pragma pack(8)
    struct S1
    {
            char c1;//0偏移量地址
            int a; // 4~7 min(4,8)=4
            char c2;//8~11  补齐到min(最大数据类型4,对齐模数8)的整数倍
    };
    struct S2
    {
            char c1;//0
            char c2;//1 min(1,8)=1
            int a;//4~7
    };
    struct S3
    {
            double d; //0~7
            char c;//8~11
            int i;//12~15 min(4,8)=4 ,4的整数被12
    };
    struct S4
    {
            char c1;//0
            struct S3 s3;//8~23 double为基准
            double d;//24~31
    };
    int main()
    {
            printf("%d\n", sizeof(struct S1));//12
            
            printf("%d\n", sizeof(struct S2));//8
     
            printf("%d\n", sizeof(struct S3));//16
            
            printf("%d\n", sizeof(struct S4));//32
            
            return 0;
    }
    
    

    运行结果:
    在这里插入图片描述
    结合内存对齐规则分析:结构体S1中第一个成员变量c1是一个char类型,占用一个字节,根据规则1,从偏移量0的位置存放;第二个成员变量i 是int类型,占用4个字节,根据规则2,取对齐模数为4,故从偏移量4的地址存放依次占用4个字节;第三个成员变量是char类型,占用一个字节,,根据规则2和3,此时应从偏移量为8的地址依次存储,此时结构体总大小为9,不是对齐模数的整数倍,应当补齐三个偏移量,最后占用9+3个字节;
    在这里插入图片描述
    结构体S2中c1同上,c2也是char型,此时的对齐模数(1和系统对齐模数8中取小值取小值)故取1,故从偏移量为1的地址存储,第三个成员变量a是int型,占用4个字节,对齐模数取4,故从偏移量为4的内存地址依次存储;最后一共占用8个字节;
    在这里插入图片描述

    根据运行结果可以发现,结构体S1和S2中的成员变量类型完全相同,只是位置不同,运行所得结果却不一样;
    总结:设计结构体的时候:既要满足对齐,又要节省空间;
    做法:让占用空间小的成员尽量集中在一起;

    展开全文
  • go结构体内存对齐

    2020-11-23 21:01:19
    由于内存对齐的原因,结构体实际占用字节数永远大于等于结构体所有字段字节数之和。没错,确实有正好相等的情况,后面我们会看到在一种什么样的机缘巧合之下他们会恰好相等。 对于结构体的每个字段,我们先来认识...
  • 什么是结构体内存对齐,有什么好处 下面先看一个例子: #include<stdio.h> int main() { struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; int i; }; printf("%d\n...
  • 为什么要内存对齐 虽然所有的变量最后都会保存到特定的地址内存中去,但是相应的内存空间必须满足内存对齐的要求,主要基于存在以下两个原因: 硬件平台原因: 并不是所有的平台都能够访问任意地址上的任意数据,...
  • 结构体内存对齐规则 一、什么是结构体内存对齐         结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的...
  • 一、存在内存对齐的原因 1、平台原因 不是所有硬件平台都能够访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因(主要原因) 数据结构(尤其是栈)应该...
  • C语言结构体内存对齐

    2019-04-10 16:44:18
    结构体所占用的内存,则为其内部所有字段内存总和: struct Student { double doubleV; long longV; int intV; float floatV[2]; char * name; int age; }sinS; int main() { printf("sin size:%d", ...
  • 结构体为什么要内存对齐,为了减少cpu内存读取的次数。 那么为什么会减少cpu内存读取的次数呢? 网上很多说法是因为cpu读取数据的粒度是4个字节,所以如果不对齐就会读两次。 我理解的是cpu读取内存是通过段指针+...
  • 结构体内存对齐详解

    2019-09-05 09:19:13
    内存对齐 先来讨论这个问题:为什么存在内存对齐? 大部分的参考资料都是如是说的: 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址 处取某些特定类型的数据...
  • C++之结构体内存对齐

    2021-05-19 16:57:04
    C++之结构体内存对齐 内存对齐原因 首先要知道,cpu是把内存当作一块一块来读取的,块的大小可以是2,4,8,16个字节,这样内存不对齐就可能会导致每次读取数据需要读取两次,内存对齐之后读取一次就行,可以大大...
  • 为什么要进行结构体内存对齐

    千次阅读 多人点赞 2018-08-10 21:59:12
    结构体内存对齐 什么是结构体内存对齐 结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的要求,而是每个成员在内存中的存储都要按照一定偏移量来存储...
  • 1. 结构体内存对齐规则   对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值   vs中的默认值为8; Linux中的默认值为4; 原则1:数据成员的对齐规则(以最大的类型字节为单位)。   结构体(struct)的...
  • 为什么有内存对齐???  “内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上,便于编译器管理数据。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐...
  • 在求结构体的大小时,绝大部分情况下不会直接等于各个成员大小的总和,编译器为了优化对结构体成员的访问总会在结构体中插入一些空白字节(内存对齐) 例如 struct S1 { char c1; char c2; int i; }; printf(...
  • 实际上,通过运行程序得到的结果是8 byte,这就是内存对齐所导致的。下面我们来介绍什么是内存对齐? 对齐准则 1、第一个成员在与结构体变量偏移量为0的地址 2、 其他成员变量要对齐到某个数字(对齐数)的整数倍的...
  • 在c/c++中内存对齐是个经常遇到的问题,现在的CPU一次读取64bit,所以Struct编译时会自动8byte对齐。 c#同样的结构体也是8byte对齐。 using System; struct ss { public int a; // 4字节 // public int aa; // 4...
  • 结构体中是存在对齐方式的,因为计算机中在32位机的情况下,是按一个字节一个地址的存储着,但是在读取内存时并不是一个字节一个字节的读取的,因为32位机一个寄存器大概能一次读取4个字节,如果每个数据都是一个...
  • 问题解答https://www.cnblogs.com/jijiji/p/4854581.html
  • 定义 理论上说,任何变量的访问其实都可以从任何的内存地址开始,即变量的存储和内存地址是无关性的。但实际情况却由于各种原因(比如可...这就是内存对齐 以下代码可以大概解释内存对齐问题: struct st{ char...
  • 1.结构体内存对齐的原因? 什么是对齐,以及为什么要对齐: 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,955
精华内容 16,782
关键字:

结构体内存对齐