简体   繁体   English

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

[英]c - casting uint8_t* to uint32_t* behaviour

I have read this question: How does casting uint8* to uint32* work?我读过这个问题: 如何将 uint8* 转换为 uint32* 工作? but I am unsure of the answer given.但我不确定给出的答案。

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.我是新手嵌入式 C 程序员,正在从事一个使用 GCC 的项目,我一直在重构代码块以减少内存使用。 An example is where I changed the data types of some variables from uint32_t to smaller sized types:一个例子是我将一些变量的数据类型从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) modifies the value passed in to data it receives on a slave port.其中func(uint32_t* ptr)修改传递给它在从端口上接收的数据的值。 I'm coming across a problem where the above code does not behave correctly when -O1 , -O2 , -O3 or -Os optimisation is enabled.我遇到了一个问题,当启用-O1-O2-O3-Os优化时,上述代码无法正确运行。 Eg 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 .例如,当通信端口和函数分别接收到值1 5 1时,为变量设置的值为0 0 1 When no optimisation is enabled, the values are set correctly.未启用优化时,值设置正确。

The code behaves correctly if I change the data types back to uint32_t .如果我将数据类型改回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?发生这种情况的原因是否与字节序/对齐有关?

What are the pitfalls of upcasting from a uint8_t pointer to a uint32_t pointer?uint8_t指针向上转换为uint32_t指针的陷阱是什么?

TLDR TLDR

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.执行诸如将uint8_t的地址传递给期望uint32_t的地址之类的操作可能会导致内存损坏、未知结果、微妙的错误以及简单易爆的代码。

DETAILS细节

First, if the function is declared as首先,如果函数被声明为

void func( uint32_t * arg );

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...).并修改arg指向的数据,将uint8_tuint16_t的地址传递给它会导致未定义的行为和可能的数据损坏 - 如果它完全运行(继续阅读......)。 The function will modify data that is not actually part of the object the pointer passed to the function refers to.该函数将修改实际上不是传递给函数的指针所指对象的一部分的数据。

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.该函数希望能够访问uint32_t的四个字节,但您只给了它一个uint8_t字节的地址。 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...).阅读甚至可能根本不起作用(继续阅读......)。

Additionally, casting the address of a uint8_t is a strict aliasing violation.此外,转换uint8_t的地址是严格的别名违规。 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.总而言之,在 C 中,您不能安全地将对象称为它不是的对象,唯一的例外是您可以引用任何对象,就好像它是由适当数量的[signed|unsigned] char字节组成的.

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.但是将uint8_t地址转换为uint32 *意味着您试图访问一组四个unsigned char值(假设uint8_t实际上是unsigned char ,现在几乎可以肯定是这样)作为单个uint32_t对象,这是严格的别名违规,未定义的行为,并且不安全。

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.有关一些恐怖故事,请参阅gcc、严格别名和恐怖故事。

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 :此外,如果你将一个对象称为它不是的东西,你可能会违反6.3.2.3 Pointers ,C (C11) 标准的第 7 段

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.如果结果指针未针对引用类型正确对齐,则行为未定义。

It's not safe even on x86 no matter what someone might tell you about x86-based systems. 无论有人告诉您有关基于 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.他们只是没有观察到它失败了。

Yet.然而。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM