结构体,位段问题

news2025/1/21 3:02:59

结构体,位段问题

  • 一、结构体
  • 二、结构体内存分配问题
  • 三、存在内存对齐的原因
  • 四、结构体传参问题
  • 五、结构体实现位段

一、结构体

 1.简单说说结构体是什么?
 结构体就是把不同的数据类型整合到一起,组成的一个数据类型!!
 2.结构体的创建和初始化

struct Stu
{
	char name[20];
	int age;
	char sex[10];
	char id[20];
};
int main()
{
	struct Stu s1 = { "zhangsan",20,"男","202131705118" };
	struct Stu s2 = {.age = 20,.id = "110",.name = "魏江南",.sex = "女"};
	printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.id);
	printf("%s %d %s %s\n", s2.name, s2.age, s2.sex, s2.id);
	return 0;
}

 3.匿名结构体类型

//匿名结构体类型
//没有写结构体名称
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
}a[20], *p;
p = &x;

 这个匿名结构体可以理解为两次定义,x,a[20],*p没有关系,因此会报错!
 1.编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。
 2.匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

 4.结构体的自引用
 结构体的子引用也就是定义链表节点的功能!

struct SLTNode
{
	int val;
	struct SLTNode* next;
}

 再写一下就是typedef一下,重新起一个名字!!!

二、结构体内存分配问题

 1.对齐规则。
 * 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
 *其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处
&&// 对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。

 - VS 中默认的值为8
 - Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

 *结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。
  * 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
1
1
1

1
 解析:(1)第一个char直接放,第二个int对齐数为4,所以前面为4个字节,后面放了4个字节,共8个字节,还有一个char没放,放完之后9个字节,结构体的总大小为最大对齐数的整数倍,最大对齐数为4,所以是12个字节。
 (2)第二问,第一个是char,第二个是char,2个字节,第三个是int,前面要4个字节才对齐,所以总共是8个字节。

struct S3
{
	double d; //8
	char c; //1
	int i;  //4
};

int main()
{
	printf("%d\n", sizeof(struct S3)); //16
	return 0;
}

 上面double 8个字节,char1个字节,要对齐所以共12个字节,int 4个字节,所以共16个字节。

struct S3
{
	double d; //8
	char c; //1
	int i;  //4
};
//
//int main()
//{
//	printf("%d\n", sizeof(struct S3)); //16
//	return 0;
//}

struct S4
{
	char c1;  //1
	struct S3 s3; //16
	double d;
};

//8+16+8=32
int main()
{
	printf("%d\n", sizeof(struct S4));//32
	return 0;
}

 第一个char为1个字节,struct S3 s3为16个字节,里面的最大对齐数为8个字节,所以总共是8+16 = 24个字节,最后一个double 是8个字节,正好对齐,来放double ,总共24+8 = 32个字节!!!

三、存在内存对齐的原因

 1.平台原因(移植原因):
 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
 2.性能原因
 数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。
这儿在说一下这个内存对齐的优势,就是浪费一点点空间,内存对齐取数据的效率高一点,是以空间换取时间的做法!

 那在设计结构体的时候,我们既要满⾜对⻬,⼜要节省空间,如何做到:
让占⽤空间⼩的成员尽量集中在⼀起
//例如:
struct S1
{
char c1;
int i;
char c2;
};
/
struct S2
{
char c1;
char c2;
int i;
};
S1 和 S2 类型的成员⼀模⼀样,但是 S1 和 S2 所占空间的大小有了⼀些区别

 3.修改默认对齐数
#pragma 这个预处理指令,可以改变编译器的默认对齐数。
#pragma pack()

#pragma pack()

1

四、结构体传参问题

 结构体传参,怎么传,传地址还是复制传整个结构体,答案是传地址,地址占用空间小,可以一部到位,也可以通过地址直接改变结构体的值!

struct S
{
	int data[100];
	int num;
};

void print1(struct S s)
{
	printf("%d\n", s.num);
}

void print2(struct S *s)
{
	printf("%d\n", s->num);
}

int main()
{
	struct S s = { .data = {0},.num = 1 };
	print1(s);
	print2(&s);
	return 0;
}

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

五、结构体实现位段

 1.什么是位段?
**位段的成员必须是int,unsigned int, signed int
**位段的成员名后面有一个数字和一个冒号!

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

int main()
{
	printf("%zd\n", sizeof(struct A));
	return 0;
}

 2.位段的内存存储问题!!!
 **位段的成员可以是unsigned int ,signed int ,char类型
  **位段的空间是按需要以4个字节或1个字节来开辟的!
  **位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。

1
1
 在vs2022中,由上面例子可以看出内存是由一个字节从右到左开辟,如果剩余空间开辟的内存不够,则另开辟一个字节,重新存储数据!!!
 3.位段的跨平台问题!
 1. int 位段被当成有符号数还是⽆符号数是不确定的。
 2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会
出问题。
 3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
 4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利⽤,这是不确定的。

位段是以节省空间为目的而创造出来的数据类型,他在申请空间时,是按比特位的形式来存储的,但是它存在跨平台问题!!!
 4.位段的应用
1

 5.位段使用的注意事项!!!
 位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。
 所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊放在⼀个变量中,然后赋值给位段的成员。
这个问题就是说,它的位段成员分配空间是按比特位来分配的,不是按字节数分配的,会存在两个位段成员有同一个地址问题,因此不能&操作!!!



 完结!!!!

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

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

相关文章

【复现】Supabase后端服务 SQL注入漏洞_48

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一: 四.修复建议: 五. 搜索语法: 六.免责声明 一.概述 Supabase是什么 Supabase将自己定位为Firebase的开源替代品,提供了一套工具来帮助开发者构建web或移动应用程序。 Sup…

【MySQL探索之旅】MySQL数据库下载及安装教程

📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有…

1921:【02NOIP普及组】过河卒

1921:【02NOIP普及组】过河卒 【题目描述】 如图,A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。 同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有…

leetcode(双指针)11.盛最多水的容器(C++详细解释)DAY9

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回…

CTFshow web(php命令执行 68-71)

web68 还是那句话,没看到flag在哪,那就优先找到flag位置 这里cvar_dump(scandir("/")); 直接输出根目录的位置,然后查看源代码,发现flag位置为flag.txt 知道flag在根目录下面的flag.txt直接访问就好了 cinclude(/flag…

【C++ 02】类和对象 1:初识类和对象

文章目录 🌈 Ⅰ 面向对象介绍🌈 Ⅱ 类的引入🌈 Ⅲ 类的定义格式1. 声明和定义不分离2. 声明和定义分离 🌈 Ⅳ 类的访问限定符🌈 Ⅴ 类的作用域🌈 Ⅵ 类的实例化🌈 Ⅶ this 指针 🌈 Ⅰ…

17 ABCD数码管显示与动态扫描原理

1. 驱动八位数码管循环点亮 1.1 数码管结构图 数码管有两种结构,共阴极和共阳极,ACX720板上的是共阳极数码管,低电平点亮。 1.2 三位数码管等效电路图 为了节约I/O接口,各个数码管的各段发光管被连在一起,通过sel端…

【c++基础】国王的魔镜

说明 国王有一个魔镜,可以把任何接触镜面的东西变成原来的两倍——只是,因为是镜子嘛,增加的那部分是反的。 比如一条项链,我们用AB来表示,不同的字母表示不同颜色的珍珠。如果把B端接触镜面的话,魔镜会把…

LeetCode.145. 二叉树的后序遍历

题目 145. 二叉树的后序遍历 分析 上篇文章我们讲了前序遍历,这道题目是后序遍历。 首先要知道二叉树的后序遍历是什么?【左 右 根】 然后利用递归的思想,就可以得到这道题的答案,任何的递归都可以采用 栈 的结构来实现&#…

Vulnhub靶机:DC2

一、介绍 运行环境:Virtualbox 攻击机:kali(10.0.2.15) 靶机:DC2(10.0.2.55) 目标:获取靶机root权限和flag 靶机下载地址:https://www.vulnhub.com/entry/dc-2,311/…

如何在 Ubuntu 上安装 ONLYOFFICE 文档 8.0

通过使用社区版,您有能力在您自己的服务器上部署 ONLYOFFICE 文档,从而使在线编辑器与 ​​ONLYOFFICE 协作平台​​​或​​其他热门系统​​进行无缝集成。 ONLYOFFICE 文档是什么 ONLYOFFICE 文档是一款全面的在线办公工具,提供了文本文档…

前端 > JS 笔试题面试考题(21-25)

简述请看下面的代码片段并回答以下问题 &#xff1f; for (var i 0; i< 5; i){var btn document.createElement(button);btn.appendChild(document.createTextNode(Button i));btn.addEventListener(click, function(){ console.log(${i} );});document.body.appendChild…

侧信道攻击是什么

侧信道攻击是什么? 侧信道攻击是一种利用系统的物理实现或实现的特定属性来获取信息的攻击方式。这些攻击利用了系统在执行特定操作时产生的信息泄漏&#xff0c;而不是直接攻击系统的计算或加密算法。侧信道攻击通常利用系统的功耗、电磁辐射、时间延迟等物理特性进行攻击&a…

【运维测试】测试理论+工具总结笔记第1篇:测试理论的主要内容(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论测试理论测试工具相关知识。Python测试理论的主要内容&#xff0c;掌握软件测试的基本流程&#xff0c;知道软件测试的V和W模型的优缺点&#xff0c;掌握测试用例设计的要素&#xff0c;掌握等价类划分法、边界值法、因…

【C语言期末项目-通讯录】-升级可动态申请内存版(手把手详细过程,期末评分A+的项目,答辩辅助神博文,建议三连点赞收藏)

目录 ​编辑 前言&#xff1a; 1.项目功能需求分析 2.文件框架说明 3.程序主框架实现 4.创建联系人结构体类型和通讯录结构体类型 4.1创建通讯录 5.程序功能实现--封装功能函数实现不同功能 5.1通讯录初始化 5.2增加联系人 5.3显示所有联系人的信息 5.4删除指定…

COMSOL方法编辑器中产生随机数(可控制随机种子)

简介 COMSOL二次开发主要在方法编辑器中进行&#xff0c;编程语言为Java。有时需要产生随机数&#xff08;比如随机生成一些球体&#xff09;&#xff0c;方法编辑器中已经存在Math.random()可直接使用。 但是&#xff0c;对于某些特殊情况&#xff0c;我希望每次运行代码产生…

最新Burp Suite入门讲解

Burp Suite的安装 Burp Suite是一款集成化的渗透测试工具&#xff0c;包含了很多功能&#xff0c;可以帮助我们高效地完成对Web应用程序的渗透测试和安全检测。 Burp Suite由Java语言编写&#xff0c;Java自身的跨平台性使我们能更方便地学习和使用这款软件。不像其他自动化测…

使用python绘制可视化的欧拉公式三维曲线图

欧拉公式应用非常广泛&#xff0c;它在研究交流电、信号分析、量子力学、极坐标切换、求反常积分以及研究任何圆周运动等方面都有着重要的应用&#xff0c;它建立了复数、自然对数、圆周率等重要数学常量之间的关系&#xff0c;描述了复数在极坐标和笛卡尔坐标之间的转换。公式…

本地Tomcat网页搭建结合Cpolar内网穿透实现公网访问

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 1.前言2.本地Tomcat网页搭建2.1 Tomcat安装2.2 配置环境…

闲来无事,写几个好看的产品宣传界面,希望您喜欢

闲来无事&#xff0c;再写几个产品宣传页 宣传页面一&#xff1a; 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&…