C语言:结构体

目录

结构体类型的声明

匿名结构体

全局结构体变量

嵌套结构体

访问结构体成员

结构的自引用

结构体变量的定义和初始化

结构体内存对齐

结构体内存对齐规则

修改默认对齐数 #pragma pack(n) 

offsetof 求结构体成员相对于结构体开头的偏移量的宏。 

为什么存在内存对齐?

结构体传参

结构体实现位段(位段的填充&可移植性)

什么是位段

位段的内存分配规则

位段的跨平台问题

位段的应用


结构体类型的声明

匿名结构体

/* 匿名结构体类型——只能用一次,即在声明的时候顺带创建一个变量 */
struct
{char name[20];int age;
} s4;

全局结构体变量

struct Stu
{char name[20];int age;
} s1, s2; // s1 s2是全局变量struct Stu
{char name[20];int age;
} s1 = {"zhanghai", 22}; // 声明并初始化全局变量s1

嵌套结构体

struct Score
{int score;char str[20];
};struct Stu
{char name[20];int age;struct Score s;
};int main()
{// 初始化局部变量s3struct Stu s3 = {"zhanghai", 22, {100, "q"}};printf("%s %d %d %s", s3.name, s3.age, s3.s.score, s3.s.str); // zhanghai 22 100 qreturn 0;
}

访问结构体成员

#include <stdio.h>/* 本例论如何声明结构体,并使用三种方式访问结构体各成员 */struct MyType
{/* 成员 */char name[20];int age;char sex[10];char tele[12];
};/* 接受结构体指针地址,struct MyType 类型int,表示一种类型;  *p是因为要指针赋值给指针变量时需加* */
void myPrintf(struct MyType *p)
{/* *p 表示使用*将指针变量p解引用,得到 *p == obj(可参考09_pointer) */printf("%s %d %s %s\n", (*p).name, (*p).age, (*p).sex, (*p).tele); // "zhanghai", 20, "nan", "15556201597"/* p 表示指针变量,结构体指针变量 -> 成员名,也就是结构体指针变量若想访问成员,需要操作符 -> */printf("%s %d %s %s\n", p->name, p->age, p->sex, p->tele); // "zhanghai", 20, "nan", "15556201597"
}int main()
{struct MyType obj = {"zhanghai", 20, "nan", "15556201597"};// 结构体对象.成员名printf("%s %d %s %s\n", obj.name, obj.age, obj.sex, obj.tele); // "zhanghai", 20, "nan", "15556201597"// 将结构体指针传入myPrintf(&obj);return 0;
}

结构的自引用

struct Node
{int data;struct Node* next;
};
typedef struct Node
{int data;struct Node* next;
}Node;

结构体变量的定义和初始化

struct Point
{int x;int y;
} p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
struct Stu        //类型声明
{char name[15];//名字int age;      //年龄
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{int data;struct Point p;struct Node* next; 
} n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

结构体内存对齐

结构体内存对齐规则

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(gcc没有编译器对齐数,对齐数就是成员自身大小)

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

struct S1
{char c1;int i;char c2;
};struct S2
{char c1;char c2;int i;
};struct S3
{double d;char c;int i;
};printf("%d\n", sizeof(struct S1)); // 12
printf("%d\n", sizeof(struct S2)); // 8
printf("%d\n", sizeof(struct S3)); // 16

修改默认对齐数 #pragma pack(n) 

/* 修改编译器默认对齐数为4,请看结构体规则第2点 */
#pragma pack(4)
struct S
{int i;    // 0double d; // 4 8 ——> 4
};
#pragma pack()#pragma pack(1)
struct Sd
{char c;int i;char c1;
};
#pragma pack()printf("%d\n", sizeof(struct S));  // 12 (修改对齐数之前是16)
printf("%d\n", sizeof(struct Sd)); // 6

offsetof 求结构体成员相对于结构体开头的偏移量的宏。 

    
struct S1
{char c1;int i;char c2;
};struct S3
{double d;char c;int i;
};// S1
printf("%d\n", offsetof(struct S1, c1)); // 0
printf("%d\n", offsetof(struct S1, i));  // 4
printf("%d\n", offsetof(struct S1, c2)); // 8
// s3
printf("%d\n", offsetof(struct S3, d)); // 0
printf("%d\n", offsetof(struct S3, c)); // 8
printf("%d\n", offsetof(struct S3, i)); // 12

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

为什么存在内存对齐?

1. 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

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

结构体传参

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

/* 结构体传参 */
struct SC
{int data[1000];int num;
};// 结构体传参
void print1(struct SC s)
{printf("%d\n", s.num);
}
// 结构体地址传参
void print2(struct SC *ps)
{printf("%d\n", ps->num);
}struct SC s = {{1, 2, 3, 4}, 1000};
print1(s);  // 传结构体
print2(&s); // 传地址

结构体实现位段(位段的填充&可移植性)

什么是位段

位段的声明和结构是类似的,有两个不同:
  1. 位段的成员必须是 int、unsigned int 或signed int 。
  1. 位段的成员名后边有一个冒号和一个数字。
struct A
{int _a : 2; int _b : 5;int _c : 10; int _d : 30; 
};

 A就是一个位段类型。

位段的内存分配规则

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

4. int 位段被当成有符号数还是无符号数是不确定的。

5. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。

6. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

7. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

struct A
{/* 上来二话不说先开辟4个字节空间,也就是 32个bit位 */int _a : 2;  // _a占2个bit位int _b : 5;  // _b占5个bit位int _c : 10; // _c占10个bit位/* 到这里发现 只剩 15 个bit位,不够存放_d的30个bit,那么会再次开辟4个字节用来存放 */int _d : 30; // _d占30个bit位
};printf("%d\n", sizeof(struct A)); // 8 未使用位段就是16个字节

位段的跨平台问题

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
  3. 器会出问题。
  4. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  5. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

总结:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在

位段的应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/151214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pip list 和 conda list的区别

PS : 网上说conda activate了之后就可以随意pip了 可以conda和pip混用 但是安全起见还是尽量用pip 这样就算activate了&#xff0c;进入base虚拟环境了 conda与pip的区别 来源 Conda和pip通常被认为几乎完全相同。虽然这两个工具的某些功能重叠&#xff0c;但它们设计用于不…

硬件开发笔记(十二):RK3568底板电路电源模块和RTC模块原理图分析

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134429973 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

庖丁解牛:NIO核心概念与机制详解 06 _ 连网和异步 I/O

文章目录 Pre概述异步 I/OSelectors打开一个 ServerSocketChannel选择键内部循环监听新连接接受新的连接删除处理过的 SelectionKey传入的 I/O回到主循环 Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 庖丁解牛&#xff1a;NIO核心概念与机制详解 02 _ 缓冲区的细节实现…

如何将本地Portainer管理界面结合cpolar内网穿透工具实现远程浏览器访问

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

Android修行手册-POI操作中文API文档

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

redis三种集群方式

redis有三种集群方式&#xff1a;主从复制&#xff0c;哨兵模式和集群。 1.主从复制 主从复制原理&#xff1a; 从服务器连接主服务器&#xff0c;发送SYNC命令&#xff1b; 主服务器接收到SYNC命名后&#xff0c;开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所…

键盘方向键移动当前选中的table单元格,并可以输入内容

有类似于这样的表格&#xff0c;用的<table>标签。原本要在单元格的文本框里面输入内容&#xff0c;需要用鼠标一个一个去点以获取焦点&#xff0c;现在需要不用鼠标选中&#xff0c;直接用键盘的上下左右来移动当前正在输入的单元格文本框。 const currentCell React.u…

【数据结构初阶】单链表SLlist

描述 不同于顺序表&#xff0c;顺序表的数据是存储在一个连续的空间里的 而链表它是链接起来的结构体地址。 所以我们不用像顺序表一样先创建一块空间出来&#xff0c;而是创建一个能存数据节点和节点与下一个节点之间的连接&#xff1b; 所以&#xff1a;“一个能存数据节点…

词向量笔记

一、词向量的世界排名比赛MTEB MTEB: Massive Text Embedding Benchmark 二、词向量的维数 词向量的维数d1一般取20~500之间

百分点科技|怎样做数据运营,才能让数据中台真正用起来?

导读&#xff1a;大多数企业用户已完成数据平台初步建设工作&#xff0c;但数据在业务运营和管理中没有发挥应有价值。数据开发工作繁重&#xff0c;数据质量问题严重&#xff0c;IT、数据和业务协作不畅&#xff0c;诸多问题依然困扰着企业用户的IT部门和数据部门。数据运营成…

起立科技(起鸿)在第25届高交会上展示透明OLED技术创新

第二十五届中国国际高新技术成果交易会 日期&#xff1a;2023年11月15日 地点&#xff1a;福田会展中心7号馆 深圳&#xff0c;2023年11月15日 — 起鸿科技&#xff0c;作为透明OLED领域的引领者&#xff0c;于今日参展了第二十五届中国国际高新技术成果交易会。这一展会将汇…

『亚马逊云科技产品测评』活动征文|通过lightsail一键搭建Drupal VS 手动部署

『亚马逊云科技产品测评』活动征文&#xff5c;通过lightsail一键搭建Drupal 提示&#xff1a;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚…

微服务架构中的 熔断和降级

文章目录 熔断判定服务的健康状态服务恢复正常 降级跨服务降级自身服务提供有损服务具体案例分析 熔断 微服务架构中&#xff0c;如果需要保障可用性&#xff0c;其中一个方式就是 熔断。熔断在微服务架构里面是指 当微服务本身出现问题的时候&#xff0c;它会拒绝新的请求&am…

大学生如何免费认证,下载,安装MATLAB

下载 打开学校图书馆官网 选择版本后&#xff0c;点击下载 注册绑定个人认证 前提&#xff01;需要有学校邮箱【以edu.cn结尾的】 进入mathworks官网 注册账户 安装 下载完后&#xff0c;打开 选择&#xff1a;setup 安装程序 勾选&#xff1a;是&#xff1b;选择&#xf…

机器学习第10天:集成学习

文章目录 机器学习专栏 介绍 投票分类器 介绍 代码 核心代码 示例代码 软投票与硬投票 bagging与pasting 介绍 核心代码 随机森林 介绍 代码 结语 机器学习专栏 机器学习_Nowl的博客-CSDN博客 介绍 集成学习的思想是很直观的&#xff1a;多个人判断的结合往往比…

身份证阅读器和社保卡读卡器Harmony鸿蒙系统ArkTS语言SDK开发包

项目需求&#xff0c;用ArkTS新一代开发语言实现了在Harmony鸿蒙系统上面兼容身份证阅读器和社保卡读卡器&#xff0c;调用了DonseeDeviceLib.har这个读卡库。 需要注意的是&#xff0c;鸿蒙系统的app扩展名为.hap&#xff0c;本项目编译输出的应用为&#xff1a;entry-default…

下厨房网站月度最佳栏目菜谱数据获取及分析PLus

目录 概要 源数据获取 写Python代码爬取数据 Scala介绍与数据处理 1.Sacla介绍 2.Scala数据处理流程 数据可视化 最终大屏效果 小结 概要 本文的主题是获取下厨房网站月度最佳栏目近十年数据&#xff0c;最终进行数据清洗、处理后生成所需的数据库表&#xff0c;最终进…

JPA整合Sqlite解决Dialect报错问题, 最新版Hibernate6

前言 我个人项目中&#xff0c;不想使用太重的数据库&#xff0c;而内嵌数据库中SQLite又是最受欢迎的&#xff0c; 因此决定采用这个数据库。 可是JPA并不支持Sqlite&#xff0c;这篇文章就是记录如何解决这个问题的。 原因 JPA屏蔽了底层的各个数据库差异&#xff0c; 但是…

竞赛 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

亚马逊第二个大语言模型 Olympus 即将上线

据外媒爆料&#xff0c;亚马逊正在训练他的第二个大语言模型——Olympus&#xff0c;很有可能在今年12月份上线。亚马逊计划将Olympus接入在线零售商店、Echo等设备上的Alexa语音助手&#xff0c;并为AWS平台提供新的功能。据说这个大语言模型规模达到2万亿&#xff08;2000B&a…