c - 将 uint8_t* 转换为 uint32_t* 行为

2024-04-18

我读过这个问题:将 uint8* 转换为 uint32* 如何工作? https://stackoverflow.com/questions/28603243/how-does-casting-uint8-to-uint32-work但我不确定给出的答案。

我是嵌入式 C 程序员新手,正在开发一个使用 GCC 的项目,并且我一直在重构代码块以减少内存使用。一个例子是我更改了一些变量的数据类型uint32_t对于较小尺寸的类型:

uint8_t colour;
uint16_t count;
uint16_t pixel;

func((uint32_t*)&colour);
func((uint32_t*)&count);
func((uint32_t*)&pixel);

Where func(uint32_t* ptr)修改传入从属端口上接收的数据的值。我遇到一个问题,上面的代码在以下情况下行为不正确-O1, -O2, -O3 or -Os优化已启用。例如当值1 5 1分别在通信端口和函数上接收,为变量设置的值是0 0 1。当未启用优化时,这些值设置正确。

如果我将数据类型更改回,代码将正常运行uint32_t。我不明白为什么我没有从编译器收到任何警告(我打开了额外警告)。发生这种情况的原因是否与字节序/对齐有关?

从a升级有哪些陷阱uint8_t指向一个的指针uint32_t指针?


TLDR

做一些类似传递地址的事情uint8_t到某个期待 a 地址的东西uint32_t可能会导致内存损坏、结果未知、微妙的错误和直接崩溃的代码。

DETAILS

首先,如果函数声明为

void func( uint32_t * arg );

并修改数据arg指向,传递给它一个地址uint8_t or a uint16_t将导致未定义的行为 https://en.wikipedia.org/wiki/Undefined_behavior以及可能的数据损坏 - 如果它运行的话(继续阅读...)。该函数将修改实际上不属于传递给函数的指针所引用的对象的数据。

该函数期望能够访问四个字节uint32_t但你只给了它一个地址uint8_t字节。其他三个字节去哪里了?他们可能会踩到其他东西。

即使函数只读取内存而不修改它,您也不知道内存中的内容而不是实际对象中的内容,因此函数的行为可能会不可预测。而且阅读可能根本不起作用(继续阅读......)。

此外,投射 a 的地址uint8_t是严格的别名违规。看严格的别名规则是什么? https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule。总而言之,在 C 中,你不能安全地引用一个对象,因为它不是,唯一的例外是你可以引用任何对象,就好像它是由适当数量的对象组成的一样。[signed|unsigned] char bytes.

但铸造一个uint8_t地址uint32 *意味着您正在尝试访问一组四个unsigned char值(假设uint8_t实际上是unsigned char,这在今天几乎肯定是正确的)作为一个单一的uint32_t对象,这是严格的别名违规、未定义的行为,而且不安全。

您因违反严格的别名规则而看到的症状可能很微妙,而且很难发现和修复。看gcc、严格别名和恐怖故事 https://stackoverflow.com/questions/2958633/gcc-strict-aliasing-and-horror-stories对于一些恐怖故事。

此外,如果您将一个对象称为它不是的东西,则可能会发生冲突6.3.2.3 指针,C(C11)标准第7款 https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未针对引用类型正确对齐,则行为未定义。

即使在 x86 上也不安全,无论别人如何告诉您有关基于 x86 的系统的信息。 https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment/46790815#46790815

如果你听到有人说,“好吧,它有效,所以那都是错的。”,好吧,他们是非常非常错误的。

他们只是没有观察到它失败了。

Yet.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c - 将 uint8_t* 转换为 uint32_t* 行为 的相关文章

  • 如何在 wpf 密码框设置一些默认文本? [复制]

    这个问题在这里已经有答案了 可能的重复 WPF 中的水印文本框 https stackoverflow com questions 833943 watermark textbox in wpf 我可以知道如何在 WPF 的密码框中放入一些
  • 获取 WSA 错误代码的格式化消息

    我在 win32 C 应用程序中使用winsock2 我将使用 MessageBox 显示可以通过调用 WSAGetLastError 检索的网络错误 我怎样才能做到这一点 我看到 FormatMessage 但我不明白如何使用它 例如 以
  • 为多线程 UDP 客户端执行“close ()”时套接字描述符未释放

    我在下面编写了 UDP 客户端 它基本上生成一个单独的线程来接收数据报 但是数据报仅在主线程中发送 现在 在 Linux 发行版上实例化 udpClient 1 UDP 客户端后按 ctrl D 实现退出循环 围绕 getline 调用 并
  • return 语句是否为按值返回的函数创建临时对象?

    当我学习 C 11 右值引用和移动语义时 我开始对函数如何返回值来初始化变量感到困惑 看下面的例子 Widget makeWidget Widget w return w Widget w1 makeWidget 这里我假设没有 RVO 即
  • Lambda、封闭变量、显示类、可序列化性和流行层

    我已经为 Compact Framework 实现了一个流行层 包括BinaryFormatter 类似序列化器 我希望能够在适当的情况下序列化编译器生成的类 这些类是由 lambda 和迭代器等产生的 这样如果 例如 lambda 及其封
  • C# 按下按钮时跳出循环

    我有一个简单的 C foreach 循环 如何在按下按钮时跳出循环 它不在backgroundWorker线程中 所以我不能使用backgroundWorker Cancellation Pending 在表单中创建一个布尔标志 将事件处理
  • 是否已经有一些基于 std::vector 的 set/map 实现?

    对于小型集合或地图 通常使用排序向量而不是基于树的向量要快得多set map 特别是对于 5 10 个元素的情况 LLVM 有一些类本着这种精神 http llvm org docs ProgrammersManual html ds se
  • 将 MyGeneration 与 Fluent NHibernate 结合使用

    我在这里找到了一个使用 MyGeneration 生成 NHibernate 代码的绝佳模板 http vucetica blogspot com 2009 01 nhibernate template for my Generation
  • 正确别名向量

    我无法在其他地方找到答案 所以我想我只需要问这个 我正在尝试获取向量 其中存储 int 指针 的别名 如下所示 void conversion Engine ENGINES The Engine class has a vector of
  • Qml 中的 FileDialog 在发布中不起作用

    我正在与以下项目合作Qt Quick Control 2 当我尝试在调试模式下运行软件时 FileDialog qml 可以完美打开 但是当我将其部署为发布模式时 它无法工作 这是我的代码 import QtQuick 2 4 import
  • 以 ASCII 字符串形式获取 MemoryStream 内容的快速方法

    我在 MemoryStream 中有一个 JSON 字符串 我使用以下代码将其作为 ASCII 字符串获取 MemoryStream memstream new MemoryStream Write a JSON string to mem
  • 提高 ASP.NET/C# 编译速度的最佳方法是什么?

    更新 请将您的答案集中在硬件解决方案上 您使用什么硬件 工具 插件来提高 ASP NET 编译和首次执行速度 我们正在寻找固态硬盘来加快速度 但现在价格确实很高 我现在有两个 RAID 0 的 7200 rpm 硬盘 但我对性能不再满意 所
  • 产量回报延迟迭代问题

    我知道yield return 利用了延迟加载 但我想知道我是否可能滥用迭代器或者很可能需要重构 我的递归迭代器方法返回给定的所有祖先PageNode包括pageNode itself public class PageNodeIterat
  • LINQ 中的左外连接

    下面的代码不断给我一个错误消息 你调用的对象是空的 var partsWithDefaults from partsList1 in p join partsList2 in d on new PartNo partsList1 PartN
  • 如何在c#中打印全尺寸图像

    我正在尝试用 C 打印图像 它是由 Adob e Acrobat 从 PDF 创建的完整 8 5x11 尺寸的 tiff 当我使用下面的代码用 C 打印它时 它垂直打印正确 但水平打印不正确 水平方向被推了大约半英寸 我将图像的原点设置为
  • C# 中的自定义按钮:如何删除悬停背景?

    我正在尝试使用 Visual Studio 2005 对我的表单 其 FormBorderStyle none 执行自定义按钮 我在链接到该按钮的 ImageList 中有我的 3 种状态按钮图像 this btnClose AutoSiz
  • 初学者友好的方法来获取所有文件和目录的列表

    使用 NET 3 0 我得到了下面的方法 它可以正确返回指定目录的所有文件和目录 以及子目录 的集合 如果可能的话 我想将其简化为仅使用我非常熟悉的结构 具体来说 有以下几点我不太清楚 1 IEnumerable
  • OpenMP 动态调度与引导调度

    我正在研究 OpenMP 的调度 特别是不同的类型 我了解每种类型的一般行为 但澄清一下何时进行选择会很有帮助dynamic and guided调度 英特尔的文档 https software intel com en us articl
  • 我如何将 C++ 与 VALA 混合起来

    我需要用 C 编写跨平台的 GUI 应用程序 但由于 C 的大多数 GUI 库都有点乏味 而且我对 C NET 非常熟悉 我发现使用 GTK 的代码 Vala 代码非常有趣 并且与其他方式相比有点容易 那么我该如何将 VAlA 与 C 混合
  • 我该怎么做才能完全关闭与mcu的tcpClient连接?

    我现在正在研究与 ESP32 中运行的 tcp 服务器的 tcp 套接字连接 通信工作正常 但我无法关闭连接 在搜索关闭 重置 tcpClient 上的解决方案后 似乎关闭 tcpClient 的正确方法应该是 tcpClient GetS

随机推荐