
目录一普通结构体类型二位段类型三枚举类型四共用体类型一普通结构体类型1结构体的内存管理首先要提醒的是结构体的内存存储不单单是顺序存储在计算机的内部结构体是按照一定的规则进行存储的我们观察以下代码#includestdio.hstruct s1{int a;char n;char m;}arr1;int main(){printf(%d, sizeof(arr1));return 0;}经过上面现象分析结构体中的成员在存储的时候具有不一样的存储形式下面就跟大家详细讲解一下结构体成员和结构体是如何存储的。结构体在内存中的存储是按照一定的对齐规则在了解对齐规则之前我们要先明白结构体中的偏移量。偏移量是数据在内存中所对应结构体起始地址的偏移位置。例如数组a中a[0]的偏移量为0a[1]偏移量为1a[2]偏移量为2。用offsetof函数可以查看偏移量其中offsetof函数在头文件stddef.h中具体代码如下#includestdio.h #includestddef.h struct s1 { int a; char b; float c; }arr; int main() { fprintf(stdout, %d\n, offsetof(struct s1, a)); fprintf(stdout, %d\n, offsetof(struct s1, b)); fprintf(stdout, %d\n, offsetof(struct s1, c)); return 0; }2结构体的对齐规则结构体内存的对齐规则如下1结构体的第一个成员放在与结构体变量的起始偏移量为0的位置2从第二个成员开始往后的每个成员都要对齐到对齐数的整数倍。对齐数结构体成员自身大小和默认对齐数的最小值其中在VS编译器上自动默认对齐数为8gcc编译器没有默认对齐数对齐数就是各成员自身的大小3结构体总大小为各个成员中最大对齐数的整数倍。4如果有嵌套结构体的情况嵌套结构体对齐到自己的最大对齐数的整数倍处而结构体的总大小是最大对齐数的整数倍。接下来我以详细代码的形式跟大家讲解其它情况同理。#includestdio.h struct s1 { int a;//对齐数4 char n;//对齐数1 char m;//对齐数1 }arr1; int main() { printf(%d, sizeof(arr1));//输出8 return 0; }然而结构体采用这种对齐规则其实是拿取空间来换时间效率。在32位机器上(4字节)机器一次性读取4字节的数据即通过4个地址线引用如果没有这种对齐当读取的数据所占用的内存不在机器所一次读取的范围时机器还要再次进行读取操作这样的话时间效率将会浪费而当有这样的对齐规则时机器将会一次性的读取数据时间效率将会提高但会空间效率将会浪费。因此我们可以理解为结构体的内存对齐是拿空间来换取时间的做法细想看来如若我们我们既要满足对齐提高时间效率又要节省空间我们要在结构体的成员所占空间小的尽量集中在一起因为空间小的成员它的对齐数较小可以在部分情况下节约空间。代码如下#includestdio.h struct s1 { char a; int b; char c; }; struct s2 { char a; char b; int c; }; int main() { fprintf(stdout, %d %d, sizeof(struct s1),sizeof(struct s2)); return 0; }3结构体的对齐数经过以上的讲述不难发现如若对齐数不同结构体的内存大小将会不同而某人对齐数我们可用#pragma这个预处理命令进行修改。修改的形式为#pragma pack(n)即修改默认对齐数为n。我们还拿以上代码进行演示#includestdio.h #pragma pack(1)//修改对齐数为1 struct s1 { char a; int b; char c; }; struct s2 { char a; char b; int c; }; #pragma pack(8)//修改对齐数为8 int main() { fprintf(stdout, %d %d, sizeof(struct s1),sizeof(struct s2)); return 0; }二位段类型1位段的形式位端也是运用结构体的结构形式但与结构体有两个不同1位段的成员必须是整型家族的类型即可以是intunsigned intsigned intcharsigned charunsigned char。2位段的成员名后边有一个冒号和一个数字这个数字表示此成员所占的比特位大小若有数据不加冒号和数字则内存大小按照正常形式所占用位段的表现形式如下struct a{int a : 2;//a占2比特位int b : 5;//b占5比特位int c : 10;//c占10比特位int d;//按正常形式占4字节};2位段的内存分配位段在内存中是按照变量类型开辟的int型开辟4字节char型开辟1字节然后查看开辟内存是否够后面成员所占内存的需要如若够用则系统不会再次开辟空间用上一个所开辟的空间如若不够用则再根据成员的数据类型开辟空间。注意虽然系统是根据成员变量类型来开辟空间的但是成员所占的而空间大小是冒号后面的那个数字如若数据太大占用的空间不够用则会在系统中当数据转换成二进制时根据二进制的形式丢掉多余的数据。如图三枚举类型枚举类型是限定有限个数据例如星期几这类可以一一列举出来的变量类型对于这些情况我们就可考虑使用枚举类型惊醒求解。枚举类型的形式如下enum color//枚举变量enum color的声明{red,//默认值为0此数值可以修改blue,//默认值为1此数值可以修改yellow//默认值为2此数值可以修改};enum color a, b, c;//定义枚举变量a,b,c要说明的是枚举类型没有太多细节处理以上的结构式其它的基本与结构体一样只需明白以上的知识点即可我就不做过多的说明了。四共用体类型1共用体的特点共用体也叫联合体联合体的成员和整个共用体是共用同一块内存空间的这样一个联合体变量的大小至少是最大成员的大小因为联合体至少有能力保存最大的那个成员的数据。联合体的结构式union s1//共用体类型{int a;char b;int c;};union s1 m, n;//建立n,m共用体变量在以上代码中共用体和数据a,b,c共占用一块内存空间也就是说他们的起始地址是一样的。代码如下#includestdio.h union s1 { int a; char b; int c; }s; int main() { fprintf(stdout, %p\n, s); fprintf(stdout, %p\n, s.a); fprintf(stdout, %p\n, s.b); fprintf(stdout, %p\n, s.c); return 0; }所以当共用体其中一个成员数据改变时去其它成员的数据也会随之改变。如图所示2共用体的大小计算根据共用体的特点我们知道共用体整个大小必须大于或等于最大成员的大小。共用体的最终内存空间并不简单等于最大成员的内存空间。当最大成员的大小不是最大对齐数的整数倍时就要对齐到最大对齐数的整数倍如下#includestdio.h #includestddef.h union s1 { char a[6];//占6字节空间,对齐数为1。数组本身的对齐数 数组元素类型的对齐数 int c;//占4字节空间对齐数为4 }s;//最大内存为6字节但最大对齐数为4要对齐到4的整数倍所以为8 int main() { s.c 0x01050408; fprintf(stdout, %d\n, sizeof(s)); return 0; }当最大成员是最大对齐数时共用体的大小为最大成员的大小如下#includestdio.h union s1 { char a;//占1字节空间,对齐数为1 int c;//占4字节空间对齐数为4 }s;//最大内存为4字节最大对齐数也为4所以为4 int main() { fprintf(stdout, %d\n, sizeof(s)); return 0; }总有关结构体类似的式子的要点以及内存管理的注意点已经讲述完了学习这些知识是为了如何灵活并巧妙的为今后复杂的问题进行运用在C/C中地址和内存管理的运用比较复杂在以后深入的学习中基本都是要通过这样的复杂空间管理来进行地址的运用。