以下是否违反了严格的别名

Does the following violates strict aliasing

考虑以下代码:

*((unsigned int*)((unsigned char *)0x400000));

它是否违反了严格的别名?

来自严格的别名规则:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

...

要发生违规,必须有类型为 unsigned char 的对象,因此当使用 unsigned int* 访问时将发生违规。

现在,(unsigned char *)0x400000 是否在地址 0x400000 构成一个 unsigned char 对象?如果不是,那么这里实际上没有存储类型为 unsigned char 的对象,因此使用 unsigned int 访问它并不违反规则。

注意以下关于对象的短语:

Object

region of data storage in the execution environment, the contents of which can represent values

NOTE When referenced, an object may be interpreted as having a particular type; see 6.3.2.1.

因此,由于 (unsigned char *)0x400000 不构成 unsigned char 对象引用(据我了解),所呈现的对象中没有 unsigned char 类型的对象代码,所以好像没有违规。

我说得对吗?


关于@Antti Haapala的回答:

如果我们假设从 0x400000unsigned char*unsigned int* 的整数到指针的转换在我的系统上具有定义的行为,没有陷阱表示并且对齐良好,并且这是为了填补标准中实现定义的差距:

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation

这会改变我问题的答案吗?

未定。该标准甚至没有说明如果将整数转换为指针会发生什么,只是结果是实现定义的,具有几种可能未定义的行为...

但可以肯定的是 *(unsigned int*)(unsigned char *)0x400000;*(unsigned int*)0x400000 在未定义性方面没有区别,因为仅使用特定值指向对象不会改变其有效类型。

另一个问题是 0x400000 处对象的类型是什么 - 如果您从未设置它,内容是 indeterminate 并且它可能没有有效的类型。阅读它会有 未定义的行为

但可以肯定的是,如果您在该地址写入类型为 float 的对象,并考虑到它是有效访问,则地址 0x400000 处对象的有效类型将为float。如果您随后使用 unsigned int 类型的左值读取该地址处的对象,这将是一个严格的别名冲突。

该标准对这些均不采取任何立场。你一个人。检查你的编译器手册。一旦你将一个整数转换为一个指针并开始在内存中查找你就没有严格遵守并且你在标准期间找不到任何支持。

从本质上讲,严格别名在处理硬件寄存器时不适用,因为委员会显然从未考虑过与硬件相关的编程方案或内存映射寄存器。

严格别名仅适用于编译器能够确定内存中实际存储内容的有效类型的情况。如果你获取一个硬件地址和左值访问它,那里的内容永远不会有编译器知道的有效类型。这意味着在读取数据时,我认为 6.5 中的这一部分将适用:

For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

你的情况 unsigned int。请注意,就严格别名和对硬件的左值访问而言,中间转换为 unsigned char* 是完全多余的。它应该被删除。

但是,如果您执行写访问,编译器可以自由地将该地址处的值视为通过写访问使用的有效类型:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.

基本上有效类型和严格别名的规则在处理硬件地址时没有意义,所以编译器不能对它们做太多。此外,此类访问通常没有任何意义,除非指针是 volatile 限定的,从而阻止任何基于严格别名的优化尝试。

可以肯定的是,在进行任何形式的嵌入式系统编程时,请始终使用 -fno-strict-aliasing 进行编译。

该标准仅尝试定义可移植程序的行为。因此,它将是否或如何支持非便携式程序的问题留给了编译器作者的判断,他们被期望比委员会更了解客户的需求。

在任何情况下,标准都不会要求实现来保证将不可知来源的整数转换为指针然后使用该指针访问存储的效果具有任何意义。无论用于访问的类型如何,有意义地处理此类代码的能力都将成为实施质量问题。如果指针不合格 volatile,无论涉及何种类型,涉及它们的操作都可能被优化掉;如果它们是 volatile,操作将根据其他 volatile 访问进行排序,同样与类型无关。

虽然某些编译器可能允许 volatile 对象与同一类型的非限定对象之间交互的可能性,但不考虑 volatile 对象与非限定对象之间的其他交互,寻求与低级代码最大兼容性的编译器将允许 volatile 访问与所有类型的所有对象之间的交互,而那些不支持的编译器可能并不总是适应它们认为不相关的对象之间的交互,即使它们碰巧具有相同的类型和相同的地址。