摘要:如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。
结构体的基础知识: 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量
程序一:
#include //声明一个结构体类型//声明一个学生类型,是 想通过 学生类型 来创建 学生变量(对象)// 描述学生 : 属性 + 名字 + 性别 + 年龄 + 电话 struct student// struct 结构体 关键字 student 结构体 标签{ char name[10]; char sex[20]; int age; char telephone[12];// 这四个变量 就是结构体的成员变量}s4,s5,s6; // 创建 结构体 全局变量// 以上所有 就是一个 结构体类型struct student s3; // 创建 结构体 全局变量int main(){ //创建 结构体变量 的方式 struct student s1; struct student s2; // 因为 这两个变量放在 main 函数里,所以是 局部变量 return 0;}
程序一:
#include struct // 缺少一个标签(名字) 这种结构体类型 称为 匿名结构体类型 { // 那么问题来了,没有名字 该 如何 创建 结构体 变量 ? char name[10]; char sex[20]; int age; char telephone[12];}x;// 只有一种方式在结构体末尾分号(;)前面 创建 结构体 全局变量struct // 缺少一个标签(名字) 这种结构体类型 称为 匿名结构体类型 { char name[10]; char sex[20]; int age; char telephone[12];}* px;// 在 匿名结构体 的 全部变量 px 前面加上 * ,该 匿名结构体类型 变成了 匿名结构体指针类型// 即 * px 是一个结构体指针int main(){ px = &x; // 经过 编译器 编译, 程序报警,该表达式 是 不合法的 //因为 编译器, 会把 它们 当做 2 种 不同类型 来处理 // 所以 两种 不同类型 的数据,是无法进行赋值 return 0;}
程序一:
#include struct node{ int data; struct node* next;// 如果 没有 * 号,也就是数 next 是本身的结构体变量,会导致这个结构体所占内存无限大。 // 这里存地址, 存的是下一个数据的地址: //结构体自引用 就是 结构体 用指针 找到 与自身同类型的 结构体变量 // 而不是说 结构体自己 包含 结构体自己 的 变量 : struct node next (error)};int main(){ return 0;}
程序二:
#include typedef struct node // 这里的 node 是不能省略的, 要不然 下面 没有这 struct node* next 类型,只能写成 node* next{ // 但是 node 是 [把 省略了 node 从而 变成 匿名结构体 的 重命名]。 是后有的, // 也就是说 node 还没有生成, 就在结构体 调用它, // 这种写法 是错误的 int data; struct node* next;}node; // node : typedef 把 结构体 struct node 简化成 nodeint main(){ node n; return 0;}
程序一:
#include struct s{ char c; int a; double d; char arr[20];};int main(){ struct s s = { "c", 100, 3.14, "hellworld" }; printf("%c %d %lf %s/n", s.c, s.a, s.d, s.arr); return 0;}
程序二:
#include struct t{ double weight; short age;};struct s{ char c; int a; double d; char arr[20]; struct t st;};int main(){ struct s s = { "c", 100, 3.14, "hellworld", {55.6,30} }; printf("%c %d %lf %s %lf %d/n", s.c, s.a, s.d, s.arr, s.st.weight, s.st.age); return 0;}
对齐数 = 编译器默认 的 一个对齐数 与 成员大小的 较小值
vs 中 默认的值为 8; gcc 没有默认对齐数(成员的大小,就是对齐数)
比如 结构体里 有一个 成员(变量) 为 整形 int 类型 为 4byte
// 而 vs 中 默认值为 8, 4 < 8, 取 4,
// 那么 该成员的 对齐数 为 4
struct s{ char c1;// 第一个成员 在与 结构体变量 偏移量为 0 的 地址处 (内存所占 1 字节) int a; // a 对齐数 是 4 ,因为 其他成员 变量 要对齐 对齐数(4) 的 整数倍 的 地址处(地址4) // 从 c1(0 地址) 后面开始(从地址 4 开始) 地址 4 处 存放 a,就是说 c1 与 a 之间 隔了 3 个 地址(1,2,3) -> 3 字节 // 此时 a 末尾地址 为 地址8 (因为 a 的存储 需要 4 byte 空间) char c2;// c2 对齐数 1 ; 其他成员 变量 要对齐 对齐数(1)的 整数倍(倍数为 1) 的 地址处 也就是紧跟 a 后面的 地址8,(char 1 byte)存完之后,末尾地址指向 9; // 无论是地址几,都是 对齐数 1 的倍数 // 至此,1+3+4+1 为 9 字节 // 结构体 总大小 为9 字节,但此时地址,不是 成员中 最大 对齐数(4) 的整数倍, // 12 满足 // 所以 结构体的大小 最后 为 12 byte};struct s2{ char c1;// 第一个成员 在与 结构体变量 偏移量为 0 的 地址处 (1字节) char c2;// 对齐数为 1 -> 其他成员 变量 要对齐 对齐数的 整数倍( 倍数为 1 ) 的 地址处(地址1) ,c2 的存储地址 紧跟在 c1 的后面(2 字节) int a;// 对齐数 4 -> 其他成员 变量 要对齐 对齐数的 整数倍( 倍数为 4 ) 的 地址处(地址4),(c1 是 0 地址,c2 是1 地址,浪费 2,3地址) // 即 来到 地址4, 也就是 a 的地址,也就是说 a 与 c2 隔了 2 个地址(浪费了2字节空间),a 的 存储 也要 占 4 字节 // 1 + 1 + 2 + 4 == 8 字节 // 成员中 最大对齐数(4) 的整数倍 // 因为 8 == 2*4 > 6 满足条件 // 所以最后 结构体总大小 为 8};int main(){ struct s s = { 0 }; struct s2 s2 = { 0 }; printf("%d/n", sizeof(s));// 12 printf("%d/n", sizeof(s2));// 8 return 0;}
12 byte ,满足成员中 最大 对齐数(4) 的整数倍, 即 结构体大小 为 12 byte
程序二:
#include struct s3{ double d;// 第一个成员 在 与 结构体 偏移量为 0 的地址处(double 8字节,此时地址 指向地址7) char c;// 对齐数 1 地址8(9字节) int i;// 对齐数 4 c 后面的 是 地址9,不满足倍数条件,地址 12 满足(浪费 9,10,11地址,即 3字节空间),即 i 的地址 是 地址12 // i 占 4 字节, // 8 + 1 + 3 +4 == 16 // 16 满足成员中 最大对齐数(8)的整数倍};int main(){ printf("%d/n", sizeof(struct s3));// 16}
程序二:
#include struct s3{ double d;// 对齐数 8 地址 7 char c;// 对齐数 1 地址 8 int i;// 对齐数 4 地址 12 i 存储 需要 4byte ,地址 16 // 结构体大小 16 byte 满足 最大 对齐数(8) 的整数倍 // 故结构体 真正大小 为 16字节};struct s4{ char c1; // 地址0, 对齐数 1 // 嵌套了结构体的情况,嵌套的结构体 对齐 到自己的 最大 对齐数(8) 的整数倍处 struct s3 s3; // 对齐地址 8 然后 结构体 s3 内存大小 为 16 byte // 存完16byte之后,地址 24 double d; // 对齐数 8 ,地址24 满足 对齐数 整数倍 地址 // 地址 24 到 地址 32 // 32 满足 最大 对齐数(8)的整数倍 // 结构体 变量 s4 内存大小 32 字节 };int main(){ printf("%d/n", sizeof(struct s4));// 32}
struct s{ char c1;// 第一个成员 在与 结构体变量 偏移量为 0 的 地址处 (内存所占 1 字节) int a; // a 对齐数 是 4 ,因为 其他成员 变量 要对齐 对齐数(4) 的 整数倍 的 地址处(地址4) // 从 c1(0 地址) 后面开始(从地址 4 开始) 地址 4 处 存放 a,就是说 c1 与 a 之间 隔了 3 个 地址(1,2,3) -> 3 字节 // 此时 a 末尾地址 为 地址8 (因为 a 的存储 需要 4 byte 空间) char c2;// c2 对齐数 1 ; 其他成员 变量 要对齐 对齐数(1)的 整数倍(倍数为 1) 的 地址处 也就是紧跟 a 后面的 地址8,(char 1 byte)存完之后,末尾地址指向 9; // 无论是地址几,都是 对齐数 1 的倍数 // 至此,1+3+4+1 为 9 字节 // 结构体 总大小 为9 字节,但此时地址,不是 成员中 最大 对齐数(4) 的整数倍, // 12 满足 // 所以 结构体的大小 最后 为 12 byte};struct s2{ char c1;// 第一个成员 在与 结构体变量 偏移量为 0 的 地址处 (1字节) char c2;// 对齐数为 1 -> 其他成员 变量 要对齐 对齐数的 整数倍( 倍数为 1 ) 的 地址处(地址1) ,c2 的存储地址 紧跟在 c1 的后面(2 字节) int a;// 对齐数 4 -> 其他成员 变量 要对齐 对齐数的 整数倍( 倍数为 4 ) 的 地址处(地址4),(c1 是 0 地址,c2 是1 地址,浪费 2,3地址) // 即 来到 地址4, 也就是 a 的地址,也就是说 a 与 c2 隔了 2 个地址(浪费了2字节空间),a 的 存储 也要 占 4 字节 // 1 + 1 + 2 + 4 == 8 字节 // 成员中 最大对齐数(4) 的整数倍 // 因为 8 == 2*4 > 6 满足条件 // 所以最后 结构体总大小 为 8};
程序一:
#include #pragma pack(4) // 设计 默认对齐数 为 4struct s{ char c1;// 1 // 浪费 3 个字节(原本要浪费 7 个 字节,现在只需 3 个字节) double d; // 8 byte 对齐 为 对齐数 4,【4与8 选择较小的】 的整数倍 的地址 // 存储 d 需要 8 个字节 加上前面浪费 3 个 和 c1 1个 字节 // 1+3+8 == 12 字节 // 这样写法,帮我们 避免 了 4 字节 的 空间浪费};#pragma pack() // 取消设置的 默认 对齐数
程序二:
那 我们把 默认对齐数 设置为 1 呢?#include #pragma pack(1) // 设计 默认对齐数 为 1struct s{ char c1;// 1 // 一个字节的都不会浪费 double d; // 8 byte 对齐 为(对齐数 1,【1与8 选择较小的】) 的整数倍 的地址 // 存储 d 需要 8 个字节 // 1+8 == 9 字节 (9 是 最大 对齐数(1)的 整数倍) // 这样写法,帮我们 避免 了 7 字节 的 空间浪费};#pragma pack() // 取消设置的 默认 对齐数// #pragma pack() 一般设置 默认 对齐数 为 2,4,8, 16 (2的次方数)
#include #include struct s{ char c; int i; double d;};int main(){ // offsetof 其实是一个宏,用来表示 成员 相对于 结构体 的 偏移量 printf("%d/n", offsetof(struct s, c));// 0 printf("%d/n", offsetof(struct s, i));// 4 printf("%d/n", offsetof(struct s, d));// 8 return 0; //而且 offsetof 的 参数 传的是 一个类型,更加说了 offsetof 是一个宏 }
#include struct s{ int a; char c; double d;};void init(struct s *tmp){ tmp->a = 100; tmp->c = "w"; tmp->d = 3.14;}void print(struct s tmp)// 传值:如果传递的结构体对象的时候,结构体过大(空间过大),容易导致 参数压栈 的 系统 开销比较大,从而导致系统性能下降。{ printf("%d %c %lf/n", tmp.a, tmp.c, tmp.d);}void print2(const struct s* tmp) // 传址 : 最好使用这种方法(节省空间),一个地址在操作系统不改变的情况,永远都是4个字节大小,{ // const 是为了防止 意外改变 结构体变量地址 指向的 值 printf("%d %c %lf/n", tmp->a, tmp->c, tmp->d);}int main() { struct s s = { 0 }; init(&s); print(s); print2(&s); return 0;}
程序一:
#include struct a // 按照以下写法写结构体成员, a 已经不是个结构体类型了,而是 一个 位段 类型了// 位段 看见成员 都是 int 类型 ,所以,它 一开始 就创建了 4 byte的 空间{ int a : 2;// 2 这里的意思是: a只需要 2 个比特位(bit) int b : 5;// 5 这里的意思是: b只需要 5 个比特位(bit) int c : 10;// 10 这里的意思是: c只需要 10 个比特位(bit) int d : 30;// 30 这里的意思是: d只需要 30 个比特位(bit)};// 一共 47 个 bit 位,由已经创建的 4byte 空间来分配空间, 很明显 空间不够 大,只能存入 a,b,c,4 byte 空间 还剩 15 bit d 放不下,怎么办呢? 在vs 环境中 系统 会舍弃(浪费)剩余的 15 bit 空间 然后, 它再向 空间申请 4 byte(32bit) 空间, 存储 d 需要 30 bt 空间,这 30 bit 的数据 就存入 这个向系统第二次申请 4 byte 的空间里 至此,数据全部存完,剩余的空间就浪费掉了,也就是说 这 位段 的 内存大小为 8 byteint main(){ struct a a; printf("%d/n", sizeof(a));// 8 byte return 0;}
&ensp;
程序一:
#include // vs 环境struct s // 因为下面 成员类型 为 char 类型,所以它 一开始 就准备 了 1 byte 空间{ char a : 3;// a 要个 3 bit 位, 由提前准备 1 byte 空间 来分配,还剩 5 bit // char b : 4;// b 要 4 bit 位,由提前准备 1 byte 空间 来分配,还剩 1 bit 空间 char c : 5;// c 要 5 bit 位,由提前准备 1 byte 空间 来分配(剩余 1 bit),不够大, // 舍弃(浪费)掉,再向内存申请 1 byte 的空间 来 存储 c (剩余 3 bit 空间) char d : 4;// d 需要 4 bit 位,剩余内存空间(3 bit)不够,把 3 bit 浪费掉(舍弃) // 再向内存申请 1 byte 空间,来存储 d,(剩余 4 bit 空间) // 至此 数据全部 存储完毕,剩余的空间 舍弃掉(浪费了) // 一共向内存 申请了 3 byte 的空间};int main(){ struct s s = { 0 }; s.a = 10;// 1010 因为 a 只有 3 bit 位 所以存入的是 010 s.b = 20;// 10100 因为 b 只有 4 bit 位 所以存入的是 0100 s.c = 3;// 0011 因为 c 只有 5 bit 位 所以存入的是 00011 s.d = 4;// 0100 因为 d 只有 4 bit 位 所以存入的是 0100 return 0;}
程序一:
enum sex// 性别{ // 枚举的可能取值(枚举常量) male,// 0 female,// 1 secret// 2};enum color // 颜色{ // 枚举的可能取值(枚举常量) red,// 0 green,// 1 blue// 2};int main(){ enum day d = mon;//枚举赋的值,只能是 枚举的 可能取值 enum sex s = male;//枚举赋的值,只能是 枚举的 可能取值 enum color c = blue;//枚举赋的值,只能是 枚举的 可能取值 blue 在枚举的里面 是 2, 那我们 可不可以这样写 enum color c = 2 ? 答案是不行,右边 2 是 int 类型, 左边的 c 是 enum color 类型 printf("%d %d %d/n", male, female, secret);// 0 1 2 printf("%d %d %d/n", red, green, blue);// 0 1 2 printf("%d/n",sizeof(s)); // 枚举大小为 4 byte ,为什么呢? 因为 枚举常量 的类型是 整形, 那 s 就是整形变量,所以输出为 4 return 0;}
程序二:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119303.html
大家好,我们每天全网搜集各行各业的研究报告,了解一个行业从阅读这个行业的研报开始,今日分享目录如下: 20211006分享目录: 2021抖音电商商家经营方法论白皮书-34页.pdf 2021中国数据智能产业发展研究报告-50页.pdf 2021公益数字化转型-56页.pdf 2021年中国一线城市出行平台调研报告-77页.pdf 2021年中国内容机构(MCN)行业发展研究报告-66页.pd...
摘要:论坛下载由于库是不带中值滤波器的,需要自己实现,所以花了点时间制作了一个章节。红色线是波形高斯白噪声均匀白噪声。第版教程发布中文显示章节论坛下载可以直接运行界面效果,也可以使用可以直接编译运行。上位机已经整合主机,下一版发布 往期周报汇总地址:http://www.armbbs.cn/for...
摘要:参一江湖只作为内容整理方,仅供学习使用。更多相关报告请查看参一江湖星球。 大家好,我们每天全网搜集各行各业的研究报告,了解一个行业从阅读这个行业的研报开始,今日分享目录如下: 20210906分享目录: 2021中国车险科技创新服务研究报告-45页.pdf 2021年中国家装行业数字化研...
大家好,我们每天全网搜集各行各业的研究报告,了解一个行业从阅读这个行业的研报开始,今日分享目录如下: 20210928分享目录: 休闲娱乐行业主题研究:本地出行,众彩纷呈-35页.pdf 休闲服务行业海南折扣观察第一期:SKU较少的GDF折扣小幅加大,其他公司相对稳定-14页.pdf 传媒行业2021年中期策略报告:从流量到留量,抓住年轻人、拥抱视频化、提升专业化-30页.pdf 传媒行业深度...
阅读 3351·2021-11-25 09:43
阅读 2257·2021-09-06 15:02
阅读 3511·2021-08-18 10:21
阅读 3253·2019-08-30 15:55
阅读 2308·2019-08-29 17:06
阅读 3506·2019-08-29 16:59
阅读 936·2019-08-29 13:47
阅读 2696·2019-08-26 13:24