与集合或联合类型相关的严格别名

msh*_*ldt 5 c standards gcc c99 strict-aliasing

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

对象的存储值只能由具有以下类型73)或88)之一的左值表达式访问:

  • (其他与问题无关的陈述被省略)

  • 成员中包括上述类型之一的集合或联合类型(递归地包括子集合或包含的联合的成员)

考虑以下:

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

MyComplex *carray = malloc(sizeof(*carray) * 10);
float *as_floats = (float *)carray;
Run Code Online (Sandbox Code Playgroud)

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

那反过来呢?即:

float *farray = malloc(sizeof(*farray) * 10);
MyComplex *as_complex = (MyComplex *)farray;
Run Code Online (Sandbox Code Playgroud)

最终,在这两种情况下,我们在此处处理的所有内容都为float,所以也许还可以吗?我不确定。

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

Per*_*xty 3

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

在结构体对象中,非位域成员和位域所在的单元的地址按照它们声明的顺序递增。指向结构对象的指针经过适当转换后,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。结构对象内可能有未命名的填充,但不是在其开头。

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

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

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

通过结构体对数组进行别名

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

我说依赖于平台,但其他调查没有提供已知的平台,其中这种结构包括填充。