当前位置: 首页 > news >正文

c语言进阶部分详解(详细解析自定义类型——结构体,内存对齐,位段)

上篇文章介绍了一些常用的字符串函数,大家可以去我的主页进行浏览。

各种源码大家可以去我的github主页进行查找:Nerosts/just-a-try: 学习c语言的过程、真 (github.com)  

今天要介绍的是:结构体的相关内容


目录

一.结构体类型的声明

1.结构的基础知识

2.结构的声明 

3.特殊的声明 

4.结构的自引用

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

 6.结构体传参

 二.结构体内存对齐  

 1.对其规则

2.存在原因

3.减少浪费 

​编辑

4.修改默认对齐数

三.位段 

1.什么是位段

2.位段的内存分配

3.位段的跨平台问题 


一.结构体类型的声明

1.结构的基础知识

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

2.结构的声明 

 结构的声明的原型:

struct tag
{
    member - list ;
} variable - list ;

eg: 

struct Student
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
}; //分号不能丢

3.特殊的声明 

匿名结构体: 

struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20], *p;

4.结构的自引用

 我们也许回想在结构中包含一个类型为该结构本身的成员是否可以呢?像下面这样

struct Node
{struct Node a1;int date[2];
};

这种情况下,需要确保结构体类型的定义是在使用它的结构体类型之前。否则,编译器将无法确定结构体类型的大小。

所以是不行的,正确的自引用方式如下:

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

注意:

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

在定义指针变量next时,使用了Node类型。由于Node类型的定义在当前代码中尚未完成,编译器无法识别Node类型

正确的如下:

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

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

struct Point
{int x;int y;
}p1; //声明结构体的同时定义变量p1struct 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};//单独结构体嵌套初始化

 6.结构体传参

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

两种调用,传参的结果都是一样的:

 但是,还是用printf2来传地址时更好:

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

 二.结构体内存对齐  

struct S1
{
     char c1 ;
     int i ;
     char c2 ;
};     这个结构体有多大呢? 
第一反应大抵是:1+4+1=6吧

 但其实:

 

 1.对其规则

1. 第一个成员在与结构体变量偏移量为 0 的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值 VS中默认的值为8
3. 结构体 总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 按照对其规则,这是上述答案的分析:

接下来再看另外一个例子: 

eg:

struct S2
{char c1;char c2;int i;
};int main()
{printf("%d", sizeof(struct S2));return 0;
}

答案便是:

2.存在原因

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

一些资料也显示说:

  1. 访问效率:内存对齐可以使结构体的成员在内存中连续存储,减少内存访问次数,提高访问效率。如果结构体成员没有进行内存对齐,可能会导致成员之间存在空隙,需要多次访问内存才能获取到所有成员的值
  2. 数据对齐:某些硬件平台要求访问特定类型的数据必须按照特定字节对齐,否则可能会导致访问错误或性能下降。例如,某些处理器要求访问双字节数据(如short类型)必须按2字节对齐,访问四字节数据(如int类型)必须按4字节对齐。如果结构体成员没有进行内存对齐,可能会导致访问错误或性能下降

 

3.减少浪费 

那我们如何尽量减少内存对齐所产生的浪费呢?

让占用 空间小的成员尽量集中 在一起

所以上述S1的例子我们可以改造成:

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};
int main()
{printf("%d\n", sizeof(struct S1));printf("%d", sizeof(struct S2));return 0;
}

结果也确实减小了内存使用:

4.修改默认对齐数

 这里我们使用#pragma,可以改变我们的默认对齐数

#pragma pack(8)//设置默认对齐数为8
struct S1
{char c1;int i;char c2;
};#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{char c1;int i;char c2;
};int main()
{printf("%d\n", sizeof(struct S1));printf("%d", sizeof(struct S2));return 0;
}

这次S2的大小便是我们最初认为的6了:


三.位段 

1.什么是位段

位段的声明和结构是类似的,有两个不同:

  1. 位段的成员必须是 intunsigned int signed int
  2. 位段的成员名后边有一个冒号和一个数字
struct A {int a : 2; //a占用2个bit位int b : 5; //b占用5个bit位int c : 10;int d : 30;
};int main()
{struct A a;printf("%d", sizeof(a));
}

不使用位段的话是占16个字节,现在是:

 

 

2.位段的内存分配

  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的(一次增加4/1个字节)
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

 

struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main()
{struct S s = { 0 };s.a = 10;s.b = 12;s.c = 3;s.d = 4;return 0;
}

3.位段的跨平台问题 

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

    这次关于结构体相关的内容就先到这里啦!                                                                           在下一篇文章中,我们将详细介绍枚举和联合体的内容。感谢大家的支持,加油!!!

 

相关文章:

c语言进阶部分详解(详细解析自定义类型——结构体,内存对齐,位段)

上篇文章介绍了一些常用的字符串函数,大家可以去我的主页进行浏览。 各种源码大家可以去我的github主页进行查找:Nerosts/just-a-try: 学习c语言的过程、真 (github.com) 今天要介绍的是:结构体的相关内容 目录 一.结构体类型的声明 1.…...

Mysql第三篇---响应太慢?数据库卡顿?如何优化?

Mysql第三篇—响应太慢?数据库卡顿?如何优化? 统计SQL的查询成本:last_query_cost 一条SQL查询语句在执行前需要确定查询执行计划,如果存在多种执行计划的话,MySQL会计算每个执行计划所需要的成本&#x…...

【计算机网络】HTTP 协议的基本格式以及 fiddler 的用法

HTTP协议的基本格式如下: 1.请求行: 包括请求THHP协议的版本、请求URI(资源路径)和HTTP方法(如GET、POST、PUT、DELETE等) GET/example.html HTTP/1.1 GET表示请求方法,/example.html表示请求的…...

人大金仓与哪吒科技达成战略合作,加快推动智慧港口建设

近日,人大金仓与哪吒港航智慧科技(上海)有限公司(以下简称“哪吒科技”)达成战略合作。双方旨在共享优势资源,联合为港口企业转型升级提供完备的技术支撑与行业解决方案。人大金仓总裁杜胜、哪吒科技总经理…...

FFmpeg工具使用集

FFmpeg工具使用集 About FFmpeg Java调用FFmpeg FFmpeg 工具: FFMPEG 用于转换多媒体文件的 命令行工具 格式之间( ffmpeg\bin\ffmpeg.exe ) ffplay 基于 SDL 和 FFmpeg 库的简单媒体播放器 ( ffmpeg\bin\ffplay.exe &#xff0…...

2024级199管理类联考之英语二2200核心词汇(第一天)

define 下定义,定范围definition 定义,清晰度identify 鉴定,识别,确认identifiable 可识别的,可辨认的identity 身份,一致determine 决心,确定determinism 宿命论,决定论judge 判断,法官/裁判behavior 举止,表现behavioral 行为的conduct v-实施,引导,指挥; n-实施方式,行为,举…...

webGL编程指南 第三章 平移三角形 TranslatedTriangle.js

我会持续更新关于wegl的编程指南中的代码。 当前的代码不会使用书中的缩写&#xff0c;每一步都是会展开写。希望能给后来学习的一些帮助 git代码地址 接着 上一节 接着做平移的转化。在本次的案例案例中主要是xy的坐标变量相加&#xff0c;同时传递个给相关变量 <!DOCTY…...

推荐一款支持异步批量下载图片的chrome插件——图片助手(ImageAssistant) 批量图片下载器

https://chrome.google.com/webstore/detail/imageassistant-batch-imag/dbjbempljhcmhlfpfacalomonjpalpko/related?hlzh-CNhttps://chrome.google.com/webstore/detail/imageassistant-batch-imag/dbjbempljhcmhlfpfacalomonjpalpko/related?hlzh-CN 安装后直接点击 会根据…...

vue 动态数字效果 vue-animate-number

安装 vue-animate-number 插件 npm install vue-animate-number &#xff08;注&#xff1a;是npm、cnpm还是yarn根据具体项目要求&#xff09; 在 main.js 中引入 import Vue from vue import VueAnimateNumber from vue-animate-number Vue.use(VueAnimateNumber)动态使用…...

10月22日,每日信息差

今天是2023年10月22日&#xff0c;以下是为您准备的13条信息差 第一、库迪咖啡计划到2025年底全球门店数量达2万家&#xff0c;库迪咖啡开业一周年全球门店数量达到6061家&#xff0c;位居全球第四 第二、超高速纯硅调制器取得创纪录突破&#xff0c;国际上首次把纯硅调制器带…...

Android系统之SurfaceFlinger

参考资料&#xff1a; Android 显示系统&#xff1a;SurfaceFlinger详解 Android 渲染机制——SurfaceFlinger 一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系 Android卡顿原理分析和SurfaceFlinger&#xff0c;Surface概念简述 Android Graphics…...

jQuery实现输入框提示并点击回显功能呢

html代码: <input type"text" id"affOrganization" name"affOrganization" class"form-control" placeholder"Search..." style"width: 300px" > <div class"search_suggest" id"gov_se…...

终端常用操作

终端操作 取消 可以用ctrl c&#xff0c;不要一个一个删除&#xff0c;会取消掉开新的一行回溯上一次的命令&#xff0c;ctrl r&#xff0c;然后键入关键词&#xff0c;直接回车运行就行 chmod x 文件名 给某个文件运行需要的权限。...

JWFD开源工作流矩阵引擎测试版本BUG20231022修正代码

public void ParamFileOutputValue(String paramfile) {String s "";String sp "";String ssp "";List<String> list new ArrayList<String>();int p 0;int k 0;//这个地方要修改为整个参数表的最大行数&#xff0c;而不是起始…...

分拣设备运动仿真

这一次我们来分享一下如何在Solidworks 中做出传送台的分拣动作并通过分拣动作生成过程动画&#xff0c;以便于我们可以用于产品展示又或者验证运行程序无误的情况下结构是否会影响输送效率。 首先创建一个新的运动算例 将窗口切换至Motion分析 在设置之前我们先理清设置传送带…...

Python【列表的反转与排序】

目录 要求&#xff1a;列表的反转 列表的排序 列表的反转&#xff1a; 方案一&#xff1a;使用reverse()方法&#xff1a;它会直接修改原始列表&#xff0c;进行反转。 方案二&#xff1a;还是使用reversed()函数&#xff1a;该函数返回一个反转后的迭代器对象&#xff0c…...

2 用TensorFlow构建一个简单的神经网络

上一篇&#xff1a;1 如何入门TensorFlow-CSDN博客 1、环境搭建 后续介绍的相关代码都是在pycharm运行&#xff0c;pycharm安装略。 打开pycharm&#xff0c;创建一个新的项目用于tensorflow编码练习&#xff0c;在Terminal输入命令&#xff1a; # 依赖最新版本的pip pip i…...

快手视频批量下载.py(10月可以用)

完整代码如下: # _*_ coding:utf-8 _*_# _*_ coding:utf-8 _*_import json import requests import time import randomheaders = """Accept: */* Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Con…...

如何用工业树莓派和MQTT平台打通OT和IT?

一、应用设备 OT端设备&#xff1a;步进电机&#xff0c;MODBUS TCP远程I/O模块&#xff0c;PLC设备 边缘侧设备&#xff1a;宏集工业树莓派&#xff1b; IT端设备&#xff1a;PC、安卓手机&#xff1b; IT端软件&#xff1a;宏集HiveMQ MQTT通信平台 二、原理 宏集工业树…...

大模型背景下软件工程的机遇与挑战

点击链接了解详情 本文作者&#xff1a;汪晟杰 导语:AISE&#xff08;AI Software Engineering&#xff09;有人说是软件工程 3.0&#xff0c;即基于大模型&#xff08;LLM - Large Language Model&#xff09;时代下的软件工程。那么究竟什么是 AISE&#xff0c;他的发展历程对…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...