c语言结构体属性之__attribute__((packed))

news2024/12/26 22:01:31

c语言结构体属性之__attribute__((packed))

0. 引出

事情是这样的,最近在做代码移植时见到了这样一段代码

typedef struct {
    uint16_t len;
    uint8_t data[PAIRING_MAX_LEN];
} pairing_rx_buffer_t;


static pairing_rx_buffer_t pairing_rx_buffer = {};
typedef struct{
    uint8_t c2[C2_BLEN];
    uint8_t e3[E3_BLEN];
    uint8_t seeds[SEEDS_BLEN];
    uint8_t icloud_id[ICLOUD_IDENTIFIER_BLEN];
    uint8_t s2[S2_BLEN];
} __attribute__((packed)) fmna_finalize_pairing_data_t;

typedef struct {
    FMNA_Service_Opcode_t finalize_pairing_opcode;
    fmna_finalize_pairing_data_t finalize_pairing_data;
} __attribute__((packed)) finalize_pairing_packet_t;


fmna_finalize_pairing_data_t    m_fmna_finalize_pairing_data

memcpy(&m_fmna_finalize_pairing_data,
       &(((finalize_pairing_packet_t *)pairing_rx_buffer.data)->finalize_pairing_data),
       sizeof(m_fmna_finalize_pairing_data));

心里飘过一万个疑问? 这是什么操作,各种结构体包含结构体,各种类型转换,各种取地址符,还把一个uint8的数组的值copy到一个结构体里面?还有结构体为什么后面还加**attribute**((packed)) 这个鬼东东 fine c语言为什么这么难

1. 解释

把代码粘贴到chatxxx他是这样回答的

这段代码定义了三个结构体:pairing_rx_buffer_tfmna_finalize_pairing_data_tfinalize_pairing_packet_t。其中,fmna_finalize_pairing_data_tfinalize_pairing_packet_t 都使用了__attribute__((packed))属性。

pairing_rx_buffer_t 结构体包含一个 uint16_t 类型的 len 成员和一个长度为 PAIRING_MAX_LENuint8_t 数组 data 成员。

fmna_finalize_pairing_data_t 结构体包含五个成员,分别是长度为 C2_BLENc2 数组,长度为 E3_BLENe3 数组,长度为 SEEDS_BLENseeds 数组,长度为 ICLOUD_IDENTIFIER_BLENicloud_id 数组和长度为 S2_BLENs2 数组。此外,该结构体使用了 __attribute__((packed)) 属性,表示该结构体的成员顺序紧密排列,没有使用任何填充字节。

finalize_pairing_packet_t 结构体包含两个成员:一个 FMNA_Service_Opcode_t 类型的 finalize_pairing_opcode 成员和一个 fmna_finalize_pairing_data_t 类型的 finalize_pairing_data 成员。同样地,该结构体使用了 __attribute__((packed)) 属性,表示该结构体的成员顺序紧密排列,没有使用任何填充字节。

在代码中,首先声明并初始化了一个 pairing_rx_buffer_t 类型的变量 pairing_rx_buffer。然后,声明了一个 fmna_finalize_pairing_data_t 类型的变量 m_fmna_finalize_pairing_data。最后,使用 memcpy 函数将从 pairing_rx_buffer.data 中复制 finalize_pairing_data 成员的数据到 m_fmna_finalize_pairing_data 变量中,复制的长度为 sizeof(m_fmna_finalize_pairing_data)。这个操作实际上是将 finalize_pairing_packet_t 结构体中的 finalize_pairing_data 成员赋值给 m_fmna_finalize_pairing_data 变量。由于 finalize_pairing_packet_t 结构体成员的顺序是紧密排列的,因此可以简单地使用指针和 memcpy 函数进行赋值。

结构体成员的顺序紧密排列,意味着成员之间没有填充字节。这就保证了结构体在内存中的布局是连续的,每个成员的地址是按照其顺序连续分布的。因此,可以使用指针和 memcpy 函数直接将结构体的内存块复制到另一个内存块中,从而实现赋值的操作。

如果结构体成员之间存在填充字节,那么结构体在内存中的布局就不再是连续的,每个成员的地址也不再是按照其顺序连续分布的。这就导致不能简单地使用指针和 memcpy 函数进行赋值,需要按照结构体成员的顺序逐个进行赋值操作。

需要注意的是,使用指针和 memcpy 函数进行赋值操作时,需要保证两个结构体的布局是相同的,即结构体成员的类型和顺序都相同。如果两个结构体的布局不同,那么就会导致数据传输或解析错误。因此,在使用指针和 memcpy 函数进行赋值操作时,需要谨慎考虑结构体的布局问题,并确保程序的正确性和可靠性。

2. 实验细究

那我懂了,它的意思是可以把一段缓存区的数据通过memcpy的方式直接给结构体的成员变量复制,因为加了__attribute__((packed))属性的结构体不会填充字节不会自动字节对齐,即每个成员变量在内存的布局是连续的,

同样的一段结构体加了__attribute__((packed))属性和没加__attribute__((packed))属性它的内存大小就非常不同

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
	int a;
	char b;
	int c;
}s1;

typedef struct
{
	int a;
	char b;
	int c;
}__attribute__((packed)) s2;

int main(void)
{
	printf("the size of s1 is %ld\n", sizeof(s1));
	printf("the size of s2 is %ld\n", sizeof(s2));
	return 0;
}

在这里插入图片描述

那如果我想把一段缓存区的数据直接copy到结构体,赋值到对应的每位成员变量呢?可以看下面这段代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
	int a;
	char b;
	int c;
}S1;

typedef struct
{
	int a;
	char b;
	int c;
}__attribute__((packed)) S2;

int main(void)
{
	S1 s1;
	S2 s2;
	char buffer[9] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
	memcpy(&s1, buffer, sizeof(s1));
	memcpy(&s2, buffer, sizeof(s2));
	printf("s1.a: %04x s1.b: %x s1.c: %04x\n", s1.a, s1.b, s1.c);
	printf("s2.a: %04x s2.b: %x s2.c: %04x\n", s2.a, s2.b, s2.c);
	printf("the size of s1 is %ld\n", sizeof(S1));
	printf("the size of s2 is %ld\n", sizeof(S2));
	return 0;
}

在这里插入图片描述

我们把代码可视化看一下

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以看到有了字节填充后赋值就变得很奇怪了不能一一对应上,加了之后就可以一一对应上了这就是__attribute__((packed))其中的一个使用场景

画一张图可能会更好理解一点

在这里插入图片描述

3. 结论

attribute((packed))会让结构体变得更加紧凑,这样我们就可以使用memcpy指针操作对结构体做一个初始化了,比如说我有一大段缓冲区的数据,我想直接把数据copy到结构体里面就可以采用这种方式,但要注意的是一定要数据的每个字节都要一一对应,不然会出现奇怪的效果,哎,这能也是c语言数据结构麻烦的表现,实现这种效果要搞这么多东西,python的话不是随便搞,我直接对list进行切割,或者用dataclass nameturple对数据进行操作就行啦 花里胡哨

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

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

相关文章

四大世界权威大学排名指标及侧重点

U.S.News、QS、ARWU、THE是公认的四大权威世界大学排名&#xff0c;每个排名的侧重点各有不同&#xff0c;故知识人网小编撰文加以介绍。 很多博士后、访问学者和联合培养博士的申请者会注重学校排名。那么都有哪些排名体系呢&#xff1f;一般来说&#xff0c;国际公认的四大权…

PLC技能在职场中的竞争力如何?

在当前的工作市场上&#xff0c;仅仅掌握PLC可能会限制您的竞争力。尽管PLC在自动化控制系统中扮演重要的角色&#xff0c;但现代工业界对多样化技能和知识的需求越来越高。 为了提高竞争力&#xff0c;以下是一些建议&#xff1a; 学习其他自动化技术&#xff1a;除了PLC&am…

人脸跟踪:基于人脸检测API的连续检测与姿态估计技术

人脸跟踪技术在视频监控、虚拟现实和人机交互等领域发挥着重要作用。通过连续的人脸检测与姿态估计&#xff0c;可以实现对人脸在视频序列中的跟踪和姿态分析。 本文将介绍基于人脸检测API的人脸跟踪技术&#xff0c;探讨其原理、应用场景以及未来发展前景。 人脸跟踪的意义和…

typescript中interface,type和Record的使用

vitevue3ts中interface&#xff0c;type和Record的使用 vitevue3ts中interface&#xff0c;type和Record的使用 interface&#xff1a;接口type&#xff1a;类型别名 基本类型组合元组类型捕捉遍历属性 扩展 interface扩展interface&#xff08;合并&#xff09;interface扩展i…

你以为的网络工程师VS实际工作中的网络工程师

我的网工朋友&#xff0c;大家好。 前两天不是端午节嘛&#xff0c;去亲戚家吃饭。饭后闲聊说起&#xff0c;他们家的电脑开不了机了&#xff0c;问我能不能修下。 我说我不太会&#xff0c;让他们打电话报修&#xff0c;会有人上门看的。 结果亲戚蹦出一句话&#xff1a;你…

Qt Widget提升为QChartView绘制曲线

1、在工程文件"*.pro"中添加"charts"组件 在工程文件"*.pro"中添加"charts"组件&#xff0c;同时在工程文件添加qcustomplot类。 QT core gui printsupport charts下载qcustomplot类。 网址&#xff1a;https://www.qcustom…

技术小知识:分布式中的BASE和CAP原则 ③

一、CAP 理论和 BASE 理论 理论是指导业界实现的纲领&#xff0c;也是提炼了多年研究的精华&#xff0c;在分布式一致性领域&#xff0c;最主要的指导理论是 CAP 和 BASE 两个。 二、CAP理论 CAP原则又称CAP定理&#xff0c;指的是在一个分布式系统中&#xff0c; Consistency&…

面试官:SpringBoot如何快速实现分库分表?

一、什么是 ShardingSphere&#xff1f; shardingsphere 是一款开源的分布式关系型数据库中间件&#xff0c;为 Apache 的顶级项目。其前身是 sharding-jdbc 和 sharding-proxy 的两个独立项目&#xff0c;后来在 2018 年合并成了一个项目&#xff0c;并正式更名为 ShardingSp…

低代码搭建100分的酷炫大屏看板,3分钟打动老板!

不久前的一个热门话题是“00后整顿职场”&#xff0c;其实完全是胡说八道&#xff0c;因为大半的00后连工作都找不到&#xff01; 在行业危机&#xff0c;裁员话题不时火爆的今天&#xff0c;别说00后了&#xff0c;90后的打工人们纷纷都有了人还没到中年的就有的危机感。别说升…

【基于Django框架的在线教育平台开发-01】账号登录及退出登录功能开发

文章目录 1 模型层开发2 视图层开发3 form表单验证4 配置urls.py5 模板层开发6 效果展示 1 模型层开发 用户数据表如下所示&#xff1a; FieldTypeExtraidintPrime Key & Auto Incrementpasswordvarchar(128)last_logindatetime(6)Allow Nullis_superusertinyint(1)usern…

适用于 SAP 解决方案的 OpenText Extended ECM(企业内容管理)

适用于SAP 解决方案的 Extended ECM 概述 创建一种更好的将您的企业内容和企业应用程序连接起来工作方式&#xff0c;并从全面的数字内容管理平台中受益&#xff0c;该平台以产品化的方式无缝集成到任何 SAP 业务应用程序中&#xff0c;无论是在本地还是在云中。 SAP 解决方案…

Flutter 组件(二)文本 与 输入框组件

Flutter开发笔记 Flutter 组件&#xff08;二&#xff09;文本 与 输入框组件 - 文章信息 - Author: Jack Lee (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChineAddress of this article:https://blog.csdn.net/qq_28550263/art…

第一章 计算机系统的概述①

一、操作系统概述 1、操作系统的概念&#xff08;什么是操作系统&#xff09; 概念&#xff1a;操作系统 (Operating System&#xff0c; 0s) 是指控制和管理整个计算机系统的硬件和软件资源&#xff0c;并合理地组织调度计算机的工作和资源的分配:以提供给用户和其他软件方便…

✅【值得收藏】超全期刊缩写查询网址

【SciencePub学术干货】英文论文写作中会插入参考文献&#xff0c;而参考文献中的期刊名称时常需要使用缩写。期刊缩写一般包括两种格式&#xff1a;JCR缩写和ISO缩写。比如 Journal of controlled release 杂志&#xff1a; 期刊名&#xff1a;JOURNAL OF CONTROLLED RELEASE…

力扣算法刷题Day47|周日总结:动态规划之背包问题

背包问题 〉题型分类 解题套路 〉动规五部曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 解题技巧 〉递推公式 问背包装满后的最大价值&#xff1a;dp[j] max(dp[j], dp[j - weight[i]] value[i]) …

跨库分页查询

背景 随着数据量的增大&#xff0c;数据库需要进行水平切分&#xff0c;例如通过业务主键id取模&#xff0c;使得数据均匀分布到不同的库中&#xff0c;随之而来的问题就出现跨库如何进行分页查询。 举例 select * from t_user order by time offset 200 limit 100 当在单库…

NXP i.MX 6ULL工业核心板规格书( ARM Cortex-A7,主频792MHz)

1 核心板简介 创龙科技SOM-TLIMX6U是一款基于NXP i.MX 6ULL的ARM Cortex-A7高性能低功耗处理器设计的低成本工业级核心板&#xff0c;主频792MHz&#xff0c;通过邮票孔连接方式引出Ethernet、UART、CAN、LCD、USB等接口。核心板经过专业的PCB Layout和高低温测试验证&#xf…

Jenkins在Ubuntu的安装问题

使用apt安装没有成功&#xff0c;各种报错。最后使用了离线安装方式。 1、安装jdk。和之前的安装jdk无异&#xff0c;增加一步 添加一个软链接 sudo ln -s /path/to/java/home/bin/java /usr/bin/java 2、下载deb包&#xff0c;然后安装 2.1、前置步骤&#xff0c;安装可能…

面向适航符合性的智能航电系统认证研究进展

摘要 民用飞机航电系统引入人工智能/机器学习技术会带来可信性、不确定性和可解释性等问题&#xff0c;有必要通过有效的符合性方法向公众与利益攸关方证实智能航电系统的适航安全性。首先&#xff0c;分析了智能航电系统的等级分类和应用现状&#xff0c;阐述了现有指南和标准…

three.js通过CubeTexture加载环境贴图,和RGBELoader加载器加载hdr环境贴图

一、使用CubeTexture进行环境贴图 1.CubeTexture使用介绍 Three.js中可以通过使用CubeTexture进行环境贴图&#xff0c;CubeTexture需要将6张图片&#xff08;正面、反面、上下左右&#xff09;包装成一个立方体纹理。下面是一个简单的例子&#xff1a; 首先需要加载六张贴图…