c - 与聚合或 union 类型相关的严格别名

标签 c gcc standards c99 strict-aliasing

我试图理解 C99 标准(C99;ISO/IEC 9899:1999 6.5/7)中以下声明的含义

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

  • (other statements unrelated to question omitted)

  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union)

考虑以下几点:

typedef struct MyComplex {
    float real;
    float imag;
} MyComplex;

MyComplex *carray = malloc(sizeof(*carray) * 10);
float *as_floats = (float *)carray;

这是否合法,因为 MyComplex 结构包含用于 as_floats 指针的兼容 float 类型?

反过来呢?即:

float *farray = malloc(sizeof(*farray) * 10);
MyComplex *as_complex = (MyComplex *)farray;

在这两种情况下,最终,我们在这里处理的所有内容都是 float,所以也许没问题?我只是不确定。

我问,因为我正在处理一个遗留代码库,它到处都在做这种事情,到目前为止,一切似乎都很好。但我觉得我们在这里是在玩火。试图弄清楚我是否需​​要在编译器命令行上禁用严格别名。

最佳答案

(我相信)所有版本的标准纵容案例 #1 的 6.7.2.1 中的注释 13 明确。您很少会得到更明确的答案! 我的重点

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

http://port70.net/~nsz/c/c99/n1256.html#6.7.2.1

是的!您可以强制转换结构以直接访问其第一个成员! 为什么有人认为这比 &(carray->real) 更好尚不清楚。但这绝对是合法的。

正如另一位评论者所指出的,我在上一个问题中讨论了案例 #2。

Aliasing Arrays through structs

结论是案例 #2 是访问成员 real 的 OK 方法。 此外,如果该结构没有内部填充(取决于平台),您甚至可以通过 imag 访问数组的第二个成员。

我说的是平台相关,但其他调查没有提供任何已知平台,这样的结构包含填充。

关于c - 与聚合或 union 类型相关的严格别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28434418/

相关文章:

frameworks - 基于 Web 的应用程序是否应该遵循 Web 标准?

c++ - 移位运算符忽略数据大小

c++ - 如何查看 C 头文件的源代码?

在 OS X 中编译 C 文件

自动矢量化最小 float 的 C 代码

c++ - 关于 C++ 标准中的第 12.7p3 段,我有以下问题

c - 为什么程序每次都给出相同的输出?

c - C编译器在功能之前需要标识符

c - 数字及其对数作为编译常量而不手动更改两者?

c++ - 如何隐藏 `A::x` 并仅在这种情况下公开 `B::x`?