c-将uint8_t *强制转换为uint32_t *行为 [英] c - casting uint8_t* to uint32_t* behaviour

查看:661
本文介绍了c-将uint8_t *强制转换为uint32_t *行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了以下问题:如何将uint8 *强制转换为uint32 *?但我不确定给出的答案.

I have read this question: How does casting uint8* to uint32* work? but I am unsure of the answer given.

我是新手嵌入式C程序员,正在使用GCC的项目中工作,并且我一直在重构代码块以减少内存使用量.一个示例是我将某些变量的数据类型从 uint32_t 更改为较小的类型:

I'm newbie embedded C programmer working on an project that uses GCC and I've been refactoring chunks of code to reduce the memory usage. An example is where I changed the data types of some variables from uint32_t to smaller sized types:

uint8_t colour;
uint16_t count;
uint16_t pixel;

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

其中 func(uint32_t * ptr)修改传递到从属端口上接收到的数据的值.我遇到一个问题,其中当 -O1 -O2 -O3 -启用了OS 优化.例如,当分别在通讯端口和函数上接收到值 1 5 1 时,为变量设置的值为0 0 1 .如果未启用任何优化,则将正确设置这些值.

Where func(uint32_t* ptr) modifies the value passed in to data it receives on a slave port. I'm coming across a problem where the above code does not behave correctly when -O1, -O2, -O3 or -Os optimisation is enabled. E.g when values 1 5 1 are received on the comms port and the function respectively, the value that is set for the variables are 0 0 1. When no optimisation is enabled, the values are set correctly.

如果我将数据类型改回 uint32_t ,则代码的行为正确.我不明白为什么我没有从编译器收到任何警告(我打开了其他警告).发生这种情况的原因与忍耐力/称赞有关吗?

The code behaves correctly if I change the data types back to uint32_t. I don't understand why I don't get any warnings from the compiler (I have extra warnings turned on). Is the reason this is happening to do with the endianess/allignment?

uint8_t 指针到 uint32_t 指针的向上转换有哪些陷阱?

What are the pitfalls of upcasting from a uint8_t pointer to a uint32_t pointer?

推荐答案

TLDR

进行诸如将 uint8_t 的地址传递给期望 uint32_t 的地址的操作可能会导致内存损坏,未知结果,细微的错误以及仅会导致错误的代码炸毁了.

Doing something like passing the address of a uint8_t to something expecting the address of a uint32_t can result in corrupted memory, unknown results, subtle bugs, and code that just plain blows up.

详细信息

首先,如果函数声明为

void func( uint32_t * arg );

并修改 arg 指向的数据,并向其传递 uint8_t uint16_t 的地址,将导致

and modifies the data arg points to, passing it the address of a uint8_t or a uint16_t will lead to undefined behavior and likely data corruption - if it runs at all (keep reading...). The function will modify data that is not actually part of the object the pointer passed to the function refers to.

该函数应该可以访问 uint32_t 的四个字节,但是您只给了它一个 uint8_t 字节的地址.其他三个字节去哪儿了?他们可能会踩别的东西.

The function expected to have access to the four bytes of uint32_t but you gave it the address of only a single uint8_t bytes. Where do the other three bytes go? They likely stomp on something else.

即使该函数仅读取内存而不进行修改,您也不知道内存中的内容,而不是实际对象中的内容,因此该功能的行为可能无法预测.而且读取可能甚至根本不起作用(请继续阅读...).

And even if the function only reads the memory and doesn't modify it, you don't know what's in the memory not in the actual object, so the function may behave unpredictably. And the read might not even work at all (keep reading again...).

此外,强制转换 uint8_t 的地址是严格的别名冲突.请参阅> 什么是严格的别名规则? .总而言之,在C语言中,您不能安全地将对象引用为不是的对象,唯一的例外是您可以引用任何对象,就像它是由正确数量的 [signed | unsigned] char 字节.

Additionally, casting the address of a uint8_t is a strict aliasing violation. See What is the strict aliasing rule?. To summarize that, in C you can not safely refer to an object as something that it is not, with the only exception being that you can refer to any object as if it were composed of the proper number of [signed|unsigned] char bytes.

但是将 uint8_t 地址转换为 uint32 * 意味着您正在尝试访问一组四个 unsigned char 值(假设> uint8_t 实际上是 unsigned char ,如今几乎可以肯定是正确的),作为一个单独的 uint32_t 对象,这是严格的别名冲突,未定义的行为,不是安全.

But casting a uint8_t address to a uint32 * means you are trying to access a set of four unsigned char values (assuming uint8_t is actually unsigned char, which is almost certainly true nowadays) as a single uint32_t object, and that's a strict aliasing violation, undefined behavior, and not safe.

您从违反严格的别名规则所看到的症状可能非常微妙,而且很难找到和修复.参见 gcc,严格别名和恐怖故事 一些恐怖的故事.

The symptoms you see from violating the strict aliasing rule can be subtle and really hard to find and fix. See gcc, strict-aliasing, and horror stories for some, well, horror stories.

此外,如果您引用的对象不是某种对象,则可能会违反 6.3.2.3指针,C(C11)标准的第7段:

Additionally, if you refer to an object as something it's not, you can run afoul of 6.3.2.3 Pointers, paragraph 7 of the C (C11) standard:

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

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.

即使在x86上也不安全有人可能会告诉您有关基于x86的系统的信息.

如果您曾经听到有人说:好吧,那是完全错误的."嗯,他们是非常非常错误的.

If you ever hear someone say, "Well, it works so that's all wrong.", well, they're very, very wrong.

他们只是没有发现它失败.

They just haven't observed it failing.

但是.

这篇关于c-将uint8_t *强制转换为uint32_t *行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆