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

C语言结构体的一些鲜为人知的小秘密

目录

一、结构体内存对齐规则:

1.1范例

1.2结构体内存对齐规则

1.3自定义默认对齐数

二、位段 

2.1什么是位段

2.2位段的内存分配

2.3位段的不足

三、枚举和联合体

3.1枚举

3.1.1枚举类型的定义

3.1.2枚举类型的使用

3.2联合体

3.2.1联合体的定义

3.2.2联合体的特点


一、结构体内存对齐规则:

1.1范例

我们来看一下结构体所占用的内存大小:

命名 A 和 B 的结构体成员都一样, 但是为什么他们占用的内存空间不一样呢?下面我们来介绍一下结构体内存的对齐规则。

1.2结构体内存对齐规则

首先我们要知道什么是对齐数,对齐数 = 编译器中默认的对齐数该成员类型变量的大小(单位是byte)中的较小值。其中,VS默认的对齐数是8,Linux无默认对齐数,对齐数是其本身。

而在结构体中存放的数据,其地址并不是严格连续存放的,而是存放在其对齐数的整数倍

编译器为结构体开创的大小,是最大对齐数的整数倍。

struct stu
{char name[20];int age;double grades;
};
int main()
{printf("%d\n", sizeof(struct stu));//结果为32return 0;
}

1.3自定义默认对齐数

之前在我们写三子棋时创建的 .h 文件中,我们就见过 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。

#pragma pack(8)//设置默认对齐数为8
struct A
{int a;short b;int c;char d;
};#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1struct B
{int a;short b;char c;int d;
};

当我们把结构体 A 和 B 的默认对齐数都设置为1时,我们可以再次计算一下他们的大小

可以看出,他们的内存竟然都变成了11,这也说明了我们设置的默认对齐数起作用了。 

二、位段 

2.1什么是位段

很多朋友可能是第一次听说过位段,它是什么?为什么能和结构体扯上关系?

接下来我们对比一下位段类型的结构体和正常的结构体:

不难看出来,位段类型是在我们正常定义的变量基础上加上了 :数字 。其实这代表了我们定义的变量所需要占用的存储空间,单位是 bit

我们分别来计算上面两种结构体的大小,我们可以得出,使用位段的结构体只需要8字节,不使用位段的结构体却要16个字节。所以,位段是用来节省空间的。

2.2位段的内存分配

我们来看个例子了解在VS中位段的内存分配。

#include<stdio.h>struct _Record_Struct
{unsigned char Env_Alarm_ID : 4;unsigned char Para1 : 2;unsigned char state;unsigned char avail : 1;
};int main()
{sizeof(struct _Record_Struct);return 0;
}

我们在VS中运行这个程序也可以得到结果是3(byte),和我们图中的一样。

位段虽然能节省空间,但当两个位段类型超过 1byte 时,还是会浪费第一个位段类型剩余的几个 bit ,开辟下一个字节空间来存放第二个位段类型 

我们再来看个例子来更直观的感受每一个 bit 位是怎么分配的。

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;
}

接下来我们通过内存看一下他们存放的数据,每四个bit位在内存中对应一个十六进制数字:

事实证明我们的理解是对的!

2.3位段的不足

我们上述只是讲解了VS中位段空间的分配,但是这仅仅是在VS中......

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

三、枚举和联合体

接下来我们介绍两种和结构体类似的自定义类型:枚举和联合体

3.1枚举

3.1.1枚举类型的定义

我们先来看一下枚举的语法:

enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};

enum + 命名,枚举中的类型用 , 隔开。

这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。赋初值后定义的类型取值从初值开始递增1,如:

enum Day
{Mon,//0Tues = 2,//2Wed,//3Thur,//4//......Fri,Sat,Sun
};

3.1.2枚举类型的使用

枚举类型能怎么使用呢? 其实它的使用在我们写一些小应用时用到的概率大一点:

enum Day//星期
{Mon = 1,Tues,Wed,Thur,Fri,Sat,Sun
};int main()
{int input = 0;scanf("%d", &input);switch (input){case Mon:case Tues:case Wed:case Thur:case Fri:printf("今天是工作日\n"); break;case Sat:case Sun:printf("今天可以休息一下啦!\n"); break;}return 0;
}

当我们用枚举常量代替 case 情况的取值时,我们的代码是不是变得清晰易懂?

枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量

3.2联合体

3.2.1联合体的定义

联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
比如:

//联合类型的声明
union Un
{char c;int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));

 union + 命名,成员之间用 ; 相隔。

3.2.2联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

联合体占用空间也遵循结构体对齐规则。

相关文章:

C语言结构体的一些鲜为人知的小秘密

目录 一、结构体内存对齐规则&#xff1a; 1.1范例 1.2结构体内存对齐规则 1.3自定义默认对齐数 二、位段 2.1什么是位段 2.2位段的内存分配 2.3位段的不足 三、枚举和联合体 3.1枚举 3.1.1枚举类型的定义 3.1.2枚举类型的使用 3.2联合体 3.2.1联合体的定义 3.…...

kubernetes问题(一)-探究Pod被驱逐的原因及解决方法

1 k8s evicted是什么 k8s evicted是Kubernetes中的一个组件&#xff0c;主要用于处理Pod驱逐的情况。在Kubernetes中&#xff0c;当Node节点资源不够用时&#xff0c;为了保证整个集群的运行稳定&#xff0c;会按照一定的优先级和策略将其中的Pod驱逐出去。这时就需要一个组件…...

论文速览【序列模型 seq2seq】—— 【Ptr-Net】Pointer Networks

标题&#xff1a;Pointer Networks文章链接&#xff1a;Pointer Networks参考代码&#xff08;非官方&#xff09;&#xff1a;keon/pointer-networks发表&#xff1a;NIPS 2015领域&#xff1a;序列模型&#xff08;RNN seq2seq&#xff09;改进 / 深度学习解决组合优化问题【…...

Denoising diffusion implicit models 阅读笔记

Denoising diffusion probabilistic models (DDPMs)从马尔科夫链中采样生成样本&#xff0c;需要迭代多次&#xff0c;速度较慢。Denoising diffusion implicit models (DDIMs)的提出是为了加速采样过程&#xff0c;减少迭代的次数&#xff0c;并且要求DDIM可以复用DDPM训练的网…...

【Java 基础篇】Executors工厂类详解

在多线程编程中&#xff0c;线程池是一项重要的工具&#xff0c;它可以有效地管理和控制线程的生命周期&#xff0c;提高程序的性能和可维护性。Java提供了java.util.concurrent包来支持线程池的创建和管理&#xff0c;而Executors工厂类是其中的一部分&#xff0c;它提供了一些…...

SpringBoot MongoDB操作封装

1.引入Jar包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency> 2.MongoDbHelper操作 /*** MongoDB Operation class* author Mr.Li* date 2022-12-05*…...

PyTorch 模型性能分析和优化 — 第 1 部分

一、说明 这篇文章的重点将是GPU上的PyTorch培训。更具体地说&#xff0c;我们将专注于 PyTorch 的内置性能分析器 PyTorch Profiler&#xff0c;以及查看其结果的方法之一&#xff0c;即 PyTorch Profiler TensorBoard 插件。 二、深度框架 训练深度学习模型&#xff0c;尤其是…...

Unity3D 简易音频管理器

依赖于Addressable 依赖于单例模板&#xff1a;传送门 using System.Collections.Generic; using System.Security.Cryptography; using System; using UnityEngine; using UnityEngine.AddressableAssets;namespace EasyAVG {public class AudioManager : MonoSingleton<…...

【李沐深度学习笔记】线性回归

课程地址和说明 线性回归p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性回归 如何在美国买房&#xff08;经典买房预测问题&#xff09; 一个简化的模型 线性模型 其中&#xff0c; x → [ x 1 , x 2 ,…...

微信收款码费率0.38太坑了

作为一个有多年运营经验的商家&#xff0c;我本人在申请收款功能时曾经走过了不少弯路。我找遍了市面上的知名的支付公司&#xff0c;但了解到的收款手续费率通常都在0.6左右&#xff0c;最低也只能降到0.38。这个过程吃过不少苦头。毕竟&#xff0c;收款功能是我们商家的命脉&…...

【学习笔记】CF1103D Professional layer

首先分析不出啥性质&#xff0c;所以肯定是暴力优化&#x1f605; 常见的暴力优化手段有均摊&#xff0c;剪枝&#xff0c;数据范围分治&#xff08;points&#xff09;&#xff0c;答案值域分析之类的。 比较经典的题目是 CF1870E Another MEX Problem&#xff0c;可以用剪枝…...

vue之Pinia

定义 Store | Pinia 开发文档 1.什么是Pinaia Pinia 是 Vue 的专属状态管理库&#xff0c;它允许你跨组件或页面共享状态。 2.理解Pinaia核心概念 定义Store 在深入研究核心概念之前&#xff0c;我们得知道 Store 是用 defineStore() 定义的&#xff0c;它的第一个参数要求是一…...

antd-vue 级联选择器默认值不生效解决方案

一、业务场景&#xff1a; 最近在使用Vue框架和antd-vue组件库的时候&#xff0c;发现在做编辑回显时** 级联选择器** 组件的默认值不生效。为了大家后面遇到和我一样的问题&#xff0c;给大家分享一下 二、bug信息&#xff1a; 三、问题原因&#xff1a; 确定不了唯一的值&a…...

分享53个Python源码源代码总有一个是你想要的

分享53个Python源码源代码总有一个是你想要的 链接&#xff1a;https://pan.baidu.com/s/1ew3w2_DXlSBrK7Mybx3Ttg?pwd8888 提取码&#xff1a;8888 项目名称 100-Python ControlXiaomiDevices DRF-ADMIN 后台管理系统 FishC-Python3小甲鱼 Flask框架的api项目脚手架 …...

【每日一题】658. 找到 K 个最接近的元素

658. 找到 K 个最接近的元素 - 力扣&#xff08;LeetCode&#xff09; 给定一个 排序好 的数组 arr &#xff0c;两个整数 k 和 x &#xff0c;从数组中找到最靠近 x&#xff08;两数之差最小&#xff09;的 k 个数。返回的结果必须要是按升序排好的。 整数 a 比整数 b 更接近 …...

并发任务队列(字节青训测试题)

需求描述 封装一个并发任务队列类&#xff0c;用于对一些异步任务按指定的并发数量进行并发执行。 /*** 延迟函数* param {number} time - 延迟时间* return {Promise} delayFn - 延迟函数(异步封装)*/ function timeout(time) {return new Promise((resolve) > {setTimeo…...

Ubuntu 安装Nacos

1、官网下载最新版nacos https://github.com/alibaba/nacos/releases 本人环境JDK8&#xff0c;Maven3.6.3&#xff0c;启动Nacos2.2.1启动失败&#xff0c;故切换到2.1.0启动成功 2、放到服务器目录下&#xff0c;我的在/home/xxx/apps下 3、解压 $ tar -zxvf nacos-serve…...

CSS 小球随着椭圆移动

html代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><…...

【李沐深度学习笔记】线性代数

课程地址和说明 线性代数p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性代数 标量 标量&#xff08;scalar&#xff09;&#xff0c;亦称“无向量”。有些物理量&#xff0c;只具有数值大小&#xff0c…...

vuejs - - - - - 递归组件的实现

递归组件的实现 1. 需求描述&#xff1a;2. 效果图&#xff1a;3. 代码3.1 封装组件代码3.2 父组件使用 1. 需求描述&#xff1a; 点击添加行&#xff0c;增加一级目录结构当类型为object or array时&#xff0c;点击右侧➕&#xff0c;增加子集点击右侧&#x1f6ae;&#x…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...