宁波俄语网站建设,企业邮箱263登录入口,在线设计家装,深圳做seo有哪些公司目录
结构体声明#xff1a;
结构体内存存储相关介绍#xff1a;
结构体的初始化与使用#xff1a;
结构体的初始化#xff1a;
结构体的使用#xff1a;
结构体对齐#xff1a;
结构体对齐原则解释#xff1a;
结构体对齐存在的原因#xff1a;
#pragma pack…目录
结构体声明
结构体内存存储相关介绍
结构体的初始化与使用
结构体的初始化
结构体的使用
结构体对齐
结构体对齐原则解释
结构体对齐存在的原因
#pragma pack( )
offsetof讲解
位段
什么是位段
位段的注意事项
位段跨平台问题
位段的实际运用
枚举
枚举的优点
联合共用体
联合体判断大小端存储 结构是一些值的集合这些值成为成员变量。结构的每个成员可以是不同类型的变量。
结构体声明
假设要用结构体描述一个人
struct Peo //Peo为结构体名字是由自己来取的
{char name[20]; //名字char tele[12]; //电话号码char sex[5]; //性别int high; //身高
};
如名字、电话号码等就称之为结构的成员变量。并且结构的成员可以是标量、数组、指针甚至是其他结构体。
当我们需要创建四个人p1、p2、p3和p4那我们应该如何创建呢
struct Peo
{char name[20]; char tele[12];char sex[5]; int high;
}p1,p2;int main()
{……;struct Peo p3,p4;return 0;
}
上述代码中跟在结构类型创建后的2个变量是作为全局变量而存在在mian( )函数中创建的则是作为局部临时变量而存在。 结构体内存存储相关介绍
结构类型创建后并不会占用内存空间它只是作为一种类型而存在而像上述代码中的p1、p2等变量会在内存中开辟一个空间进行存放是作为一种变量存在 类比记忆 结构类型是房屋建造的图纸而结构体变量是实实在在存在的房子 结构体的初始化与使用 笔者在此先创建了以下两个结构类型第二个结构类型存在了结构体嵌套的现象
struct Peo
{char name[20]; char tele[12];char sex[5]; int high;
}struct St
(struct Peo p;int num;float f;
};结构体的初始化
int main()
{……;struct Peo p1 {zhangsan, 15596668862, 男, 181};struct St p2 { {lisi, 15596668888, 女, 168},100,3.14f};return 0;
}
结构体的使用
如果需要使用上述代码中 zhangsan 这个名字则需要 p1.name如果需要使用 lisi这个名字则需要 p2.p.name 。类似于数组下标就是对结构体元素的指向。
而对于结构体的使用共有两种方式来表示其一为上述的 结构体变量.成员变量、结构体指针-成员变量。 函数传参时参数是需要压栈的 如果传参一个结构体对象的时候结构体过大参数压栈的系统开销比较大所以会导致性能的下降同时因为传参以后函数需要创建形式参数所以在传参以后如果结构体过大实参字节大小过大形参内存占用也同样会比较多这也就致使了内存空间的浪费。 而传参时如果传的是结构体指针它是指向一个结构体整体的指针只有4或8字节不同环境下编译运行的区别相较于结构体变量大大节省了空间。 综上所述结构体传参的时候要传结构体的地址。 而我们在声明结构体的时候可以不完全的声明。
比如
struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20],*p;
上面的两个结构在声明的时候省略掉了结构体标签而对于这种匿名结构体类型会有以下两种问题
1.结构体类型声明完以后结构体变量只能在一处创建即在结构体类型声明后创建
2.对于 p x 编译器会把上面的两个声明当成完全不同的两个类型所以是非法的 结构体对齐
而在结构体的使用中我们需要掌握结构体的对齐规则
1.第一个成员在与结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字对齐数的整数倍的地址处 对齐数 编译器默认的一个对齐数与该成员大小的较小值 例如Visual studio中默认的值为8 3.结构体总大小为最大对齐数每个成员变量都有一个对齐数的整数倍
4.如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处
5.结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍
6.数组可以看成某些个单个变量的集合拆分开来不难发现数组的对齐数就是它的类型对齐数
7.假设偏移量为0的地址处为0x0012ff40那么偏移量为1的地址处为0x0012ff41 结构体对齐原则解释
struct S2
{char c1;int i;char c2;
}s2;
//于vscode2022中进行的
如上述代码c1作为字符型变量占用1字节vscode的默认对齐数为81字节小于8字节因此对齐数为1同理 i 应该对齐数为4c2对齐数为1 注蓝色地址存放的是c2绿色地址存放的是i
在结构体存放时除第一个成员变量以外其余的成员变量要对齐到自身对齐数的整数倍处例如i的对齐数为4那么就需要存放在4、8、12、4n(n 4, n Z) 位置处两变量之间余留的直接舍去
而首成员变量存放的偏移为0的位置处可以看成是任何数的0倍。
同时该结构体的最大对齐数为4即i的对齐数所以偏移量8可以作为结构体的整体大小那么该结构大小为9字节
struct S3
{char c1;struct S2 s2 //其中的最大对齐数为4char c2;
};
对于上述代码笔者在刚刚已经介绍过嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处因此就是从偏移量为4位置处开始存放存放到偏移量12处再存放一个c2整体大小为4的倍数结果为17字节 结构体对齐存在的原因
1.平台原因(移植原因: 不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。
2.性能原因 数据结构尤其是栈应该尽可能地在自然边界上对齐。 原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。 总而言之 结构体的内存对齐就是拿空间来换取时间的做法 因此我们在设计结构体的时候如果要既做到对齐又要节省空间就应该 让占用空间小的成员尽量集中在一起 #pragma pack( )
作用是调整默认对齐数例如#pragama pack(1)就是在说默认对齐数为1 offsetof讲解
offsetof是用来看某结构体成员变量的存放偏移量的
例
还是以上述代码为例offsetof(struct s2, c2)结果为8因其偏移量为8offsetof(struct s2, i)结果为4因其偏移量为4 位段 什么是位段 上述代码当中整型变量应该为4字节即32比特而_a: 2就是将a这个变量变成2比特
有时候我们不需要某个变量占用很大空间例如某个变量只会是0或1但是直接开辟必定会占用32比特这种情况下我们就需要使用位段
而上述代码中是以整型大小为标准来开辟空间的 因此先开辟了32比特然后存放了 251017 以后再存放30超过了32比特因此又开辟了32比特的内存空间存放30比特的数据 在上述代码中先是开辟了8比特存放7比特内容然后又开辟了8比特存放5比特内容最后开辟了8比特存放4比特内容因此总共开辟了3字节 而对究竟体现出来是几编译器是根据16进制来判断的并且以2进制存入数据每个数据占多少比特已经规定好了计算时将四个比特位划分成一份来计算如上图编译器是从左往右来计算从右往左来存放先是a为10二进制为1010有3个比特位来存放因此存入内存以后为010b为12存入1100剩余1比特舍弃c为3存入011剩下空间的直接舍弃d为4与上同理
计算时以四个比特位为一份先是第一个字节结果是 2^2 2^1 62^1 2以此类推结果为62 03 04 位段的注意事项 1.位段的成员可以是int、unsigned int、signed int 或者 char属于整型家族类型 2.位段上的空间是按照需要以4个字节int或1个字节char的方式来开辟的 3.在使用位段时最好只创建一种变量的位段 4.位段所改变的大小必须 ≤ 其类型本身例如整型数据最多可以设置其为32比特 5.位段涉及很多不确定因素位段是不垮平台的注意需要移植的程序应该避免使用位段 位段跨平台问题 1.int位段被当成有符号数还是无符号数是不确定的 2.位段中的最大位数目不确定整型数据在16位机器中最大为16比特而在32位机器中为32比特 3.位段中的成员在内存中从左往右分配还是从右往左分配尚未定义 4.当一个结构包含两个位段第二个位段成员较大无法容纳于第一个位段剩余的位时是舍弃剩余的还是继续利用这是不确定的 位段的实际运用
例如网络传输一个数据从我这传到别人电脑里是需要通过复杂的网络传输的如下图所示 在这一过程中所需要的比特大小各不相同因此需要位段来控制大小加快传输速度 枚举 形如上述代码即为枚举笔者在此枚举了星期分别是星期一至星期日 enum Day 作为自定义类型存在因此可以看成一种数据类型创建变量时也是
数据类型 变量名称 某成员变量
如上代码周一到周三打印出来分别为 0、1、2这表明了枚举中的成员是从0开始往后延续若我们想让星期一打印出来是1我们可以进行如下操作 这时打印结果如下 枚举的优点 1.增加代码的可读性和可维护性 2.和define定义的标识符比较枚举有类型检查更加严谨 3.防止命名污染封装 4.便于调试 5.使用方便一次可以定义多个变量 define M 100
int i M
如上代码机器在编译时会变成100M消失了然而通过枚举的方法定义的成员变量本身不会消失 联合共用体
联合是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员而这些成员共用内存中的同一块空间因此也叫共用体 如上述代码如果我们要打印两个变量的地址以及整个联合体的大小 最后的结果为 原因解释 在上述代码中先是存放了整型变量a共4字节然后存放了字符型变量c1字节和已经开辟好的4字节共用同一个空间因此上述代码中a、c的地址为同一个同时联合体大小为4 注联合的成员是共用同一块空间的这样一个联合变量的大小至少是最大成员的大小因为联合至少得有能力储存最大的那个成员 联合体判断大小端存储
在讲解大小端以前我们先要了解好大小端的概念 假设存在一个整型变量a且 a 1那么他存放在内存空间中即为0x 00 00 00 01 如果是 01 00 00 00 //由低位到高位 即为小端 如果是 00 00 00 01 //由低位到高位 即为大端 可以通过上述代码来判断计算机存储是大端还是小端
check_sys( )函数共有以下两种实现方式 1.强制转换方法 int a 1; return *(char*)a; //先将a的地址取出即01 00 00 00 或者 00 00 00 01 //然后判断最开始的两位所以应该是1字节的元素即char型因此 //将a变量强制转换成char*现在是 01 或 00那么返回该地址数据 //结果为 0 或 1 2.联合体方法 union Un { char c; //先是 01 00 00 00然后取出 01 int i; }u; u.i 1; return u.c; } 注联合体也需要满足结构体对齐原则
例如
union Un
{char arr[6];int i;
}; 在开辟了6字节空间以后需要进行对齐因此总共开辟了9字节