【日志记录】---编译器内存对齐优化导致结构体指针引用成员出现地址错位

一:问题现象

在一个跨线程数据处理消息的时候出现了以下内存错位现象,在结构体指针引用的时候出现了成员数据异常

1.【数据源】线程A消息里面赋值的数据

//字节流
message.data[0] = (unsigned char)model_brake_disable_type_read();
message.data[1] = (unsigned char)(temp & 0xff);
message.data[2] = (unsigned char)((temp >> 8) & 0xff);

2.【目标结构体】线程B知道线程A该条消息的结构体,定义了专门的结构体来套字节流中的数据 

typedef struct    //目标结构体
{unsigned char break_disable_type;unsigned short break_disable_time;
}break_disable_info_t;

3.【问题出现】线程B通过直接打印和结构体成员引用的方式分别输出内容,发现结构体第二个成员输出内容异常❌

//套结构体体指针,以成员的形式引用data内容
break_disable_info_t *disableFrame = (break_disable_info_t *)message->data;printf("[pad] type%d\r\n", message->data[0]);    //输出1,正确
printf("[pad] time%d\r\n", (*((short*)(message->data+1))));    //输出60,正确printf("[pad] type%d\r\n", disableFrame->break_disable_type);    //输出1,正确
printf("[pad] time%d\r\n", disableFrame->break_disable_time);    //输出0,错误

4.【反复调试】卡这里一直想不通,语法各方面都不存在问题,一直调试打印成员变量地址,结构体和成员大小发现了异常地方

发现两个结构体成员并不连续,中间出现了一个空位

进一步调试发现原本3个字节大小的结构体,在内存中占用了四个字节的位置,这正是导致输出数据异常的原因,多出的一个字节导致数据引用出现了错位

printf("[pad] p:%p, size:%d\r\n", disableFrame_p, sizeof(break_disable_info_t_));

二:原因解析

起初反复检查,查看之前代码也是这样处理的,没有任何问题,反复调试差点放弃打算换一种写法放过这个问题,最终还是比较犟,经过上面一顿懵逼和调试后,怀疑可能是编译器内存优化,找了一下资料得到一下结论:

在C语言中,struct的大小通常取决于其成员的类型、数量以及可能的内存对齐(padding)。当你定义了如下的结构体:

typedef struct  
{  char break_disable_type;  unsigned short break_disable_time;  
} break_disable_info_t_;

char类型通常占用1个字节,而unsigned short类型在大多数现代系统上占用2个字节。但是,由于数据对齐的需要,编译器可能会在char成员后面插入填充字节(padding),以确保unsigned short从适当的地址开始。

数据对齐是许多系统为了提高访问性能而采取的一种策略。对于某些处理器,从一个对齐的地址读取或写入数据比从一个未对齐的地址更快。此外,一些处理器甚至无法从未对齐的地址访问数据,或者这样做会导致硬件异常。

在你的例子中,char后面可能有一个填充字节,以确保unsigned short从2的倍数地址开始(这取决于编译器的具体实现和平台的对齐要求)。因此,整个结构体的大小可能是:

  • char:1字节
  • 填充(padding):1字节(为了对齐unsigned short
  • unsigned short:2字节

总共 4 字节。

你可以通过sizeof运算符来检查结构体的大小,如下所示:

#include <stdio.h>  typedef struct  
{  char break_disable_type;  unsigned short break_disable_time;  
} break_disable_info_t_;  int main() {  printf("Size of break_disable_info_t_: %zu bytes\n", sizeof(break_disable_info_t_));  return 0;  
}

如果你在输出中看到4,那么说明编译器确实在charunsigned short之间插入了一个填充字节。如果你想要避免这种填充(在某些情况下,比如内存使用非常关键时),你可以使用特定的编译器指令或属性来控制对齐,但这通常不是推荐的做法,除非你有明确的理由。

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

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

相关文章

DirClass

DirClass 通过分析&#xff0c;发现当接收到DirClass远控指令后&#xff0c;样本将返回指定目录的目录信息&#xff0c;返回数据中的远控指令为0x2。 相关代码截图如下&#xff1a; DelDir 通过分析&#xff0c;发现当接收到DelDir远控指令后&#xff0c;样本将删除指定目录…

加密杂谈:Base 向上,BSC 向下

Aerdrome 价格走过一轮&#xff0c;Base 一己之力扶持起巅峰 1B Mcap, 2B FDV 的百倍币&#xff0c;秀出了肌肉&#xff0c;其所带来的正外部性也进一步盘活了 Base 生态 反观 BSC 本轮哪怕靴子落地依然没个响&#xff0c;差距在哪里&#xff1f;本 Thread 将以此为切入点探讨…

Material Studio 计算分子静电力、电荷密度以及差分电荷密度

1.先打开Material Studio导入要计算的分子cif文件或者mol文件&#xff0c;直接Flie-Import 2.高斯几何优化一下结构&#xff0c;参数按照我的设置就行&#xff0c;一般通用&#xff0c;后面出问题再调整 3.点完Run后会跳出很多计算过程&#xff0c;不用管&#xff0c;等他计算完…

【UE】利用物理学放置模型(以堆积石块为例)

目录 效果 步骤 一、准备工作 二、设置石块碰撞 三、绘制石块 效果 步骤 一、准备工作 1. 在虚幻商城中安装“Physical Layout Tool”插件 2. 在虚幻编辑器中勾选插件“Physical Layout”插件 3. 在Quixel Bridge中将我们所需要的石块资产添加到项目中 这里我们导入…

typescript 对象数组和函数

typescript 对象数组和函数 对象 在JavaScript中&#xff0c;对象属于非原始类型。对象也是一种符合数组类型&#xff0c;由若干个对象属性构成。对象属性可以是任意数据类型&#xff0c;比如数组&#xff0c;函数或者对象等。当对象属性为函数的时候&#xff0c;称为方法。 …

ubuntu20安装colmap

系统环境 ubuntu20 &#xff0c;cuda11.8 &#xff0c;也安装了anaconda。因为根据colmap的官方文档说的&#xff0c;如果根据apt-get安装的话&#xff0c;默认是非cuda版本的&#xff0c;而我觉得既然都安装了cuda11.8了&#xff0c;自然也要安装cuda版本的colmap。 安装步骤…

[Scrcpy]数据线连接安卓手机投屏windows电脑[win控制安卓手机]比Samsung Dex好用

配置好&#xff0c;只需要两步即可完成安卓手机投屏windows 第一步&#xff1a;usb线连接windows电脑 第二步&#xff1a;cmd输入投屏命令srccpy 搞定 前言/背景 一些视频资料只能下载到手机&#xff0c;很不喜欢手机那么小屏幕播放&#xff0c;播放很不方便 在家的话可以投…

做题速度太慢了,面不上

没办法&#xff0c;之前练了一个月的sql。两个月不写&#xff0c;现在差不多忘干净了。工作空窗期&#xff0c;或者休息期不能太久&#xff0c;不然学再多的内容都可能会忘完的。 sql题&#xff0c;腾讯四道sql题&#xff0c;限时45分钟完成。我只做了一道&#xff0c;还没做完…

uniapp video 层级覆盖

层级覆盖 cover-view组件 我这里做了个判断 监听全屏时隐藏按钮 根据项目需求自行更改

uts插件开发-继uniapp原生插件nativeplugins,uts插件开发可直接操作原生安卓sdk等,支持uniappx,支持源码授权价格等等

1.创建uts项目 2.创建uts插件cf-takepic 3.在index.uts中编写原生安卓代码&#xff0c;首先定义一个函数方法&#xff0c;在页面中看是否可引用成功 uts函数代码 /*** 拍照函数*/ export const takepicfunction():void{console.log("11111111") } index.vue代码 …

Spring Cloud 整合Sentinel

1、引入依赖 版本说明 alibaba/spring-cloud-alibaba Wiki GitHub 父pom <spring.cloud.version>Hoxton.SR12</spring.cloud.version> <spring.cloud.alibaba.version>2.2.10-RC1</spring.cloud.alibaba.version>Sentinel应用直接引用starter <…

网络1--通信过程的理解

1.封装与解包 通信的过程就是不断的封装和解包的过程 封装即就是按照“应用”“传输” “网络” “链路” 层&#xff0c;封装给每一层都加上相应的包头&#xff08;每一层都有协议&#xff0c;&#xff09;解包就是接受到的包文被一层层去掉相对应的包头。 任何一层的协议都…

分布式锁概述

什么是分布式锁 分布式锁是一种在分布式计算环境中用于同步访问共享资源的机制。它的主要目的是在一个分布式系统中&#xff0c;当多个进程或服务需要同时访问同一个资源时&#xff0c;确保任一时刻只有一个进程或服务能够执行涉及该资源的关键操作。这类似于传统单体应用中的…

抖音小店——服务体验,决定店铺生死的关键

哈喽~我是电商月月 新手做抖音小店&#xff0c;是不是觉得“选品”是整个抖店运营过程中最重要的操作 选品在前期确实非常重要&#xff0c;新店铺没有销量&#xff0c;没有评分本身就不好出单&#xff0c;你又不是厂家可以把价格压到最低做促销转化&#xff0c;想出单就只能把…

FTP协议与工作原理

一、FTP协议 FTP&#xff08;FileTransferProtocol&#xff09;文件传输协议&#xff1a;用于Internet上的控制文件的双向传输&#xff0c;是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的FTP应用程序&#xff0c;而所有这些应用程序都遵守同…

数据结构——链表专题3

文章目录 一、判断链表是否有环二、返回入环的第一个节点三、随机链表的复制 一、判断链表是否有环 原题链接&#xff1a;判断链表是否有环 这道题可以使用快慢指针&#xff0c;fast一次走两步&#xff0c;slow一次走一步&#xff0c;如果有环&#xff0c;它们在环里面必定会…

音频数字信号I2S一些知识理解

(1)I2S单向基本传输需要几根线传输音频信号? 3根线 LRCK SCLK(也叫BLK) DATA(单向) (2)如何理解I2S MASTER或者SLAVE的模式&#xff1f; codec的i2s作为slave mode,LRCK和SCLK来自于soc主控端,codec端自动检测MCLK和LRCK codec的i2s作为master mode,codec通过MCLK LRCLKDIV…

【Diffusion实战】训练一个类别引导diffusion模型(Pytorch代码详解)

又学习了一种方法&#xff0c;类别引导diffusion模型&#xff0c;使用mnist数据集&#xff0c;记录一下它的用法吧。 Diffusion实战篇&#xff1a;   【Diffusion实战】训练一个diffusion模型生成S曲线&#xff08;Pytorch代码详解&#xff09;   【Diffusion实战】训练一个…

基于51单片机ESP8266wifi控制机器人—送餐、快递

基于51单片机wifi控制机器人 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; ​功能介绍 具体功能&#xff1a; 1.L298N驱动电机&#xff0c;机器人行走&#xff1b; 2.装备红外线感应检测到周围环境&#xff0c;进行行程判断&#xf…

【探索Java编程:从入门到入狱】Day4

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…