阅读本文我了解到,如果它们具有兼容的成员,您可以对结构进行别名(即不违反标准),即给定以下结构:
typedef struct {
uint32_t a;
uint32_t b;
} Frizzly;
以下将破坏别名规则:
uint32_t foo(uint16_t *i) {
Frizzly *f = (Frizzly *)i;
return f->a;
}
但以下不会:
uint32_t foo(uint32_t *i) {
Frizzly *f = (Frizzly *)i;
return f->b;
}
因为所讨论的“聚合类型”包含与我们正在转换为它的指针兼容的类型,即指向类型的指针uint32_t
可以转换为包含类型成员(或成员)的结构,uint32_t
而不会破坏别名规则。
首先,我是否理解正确?
其次,结构中(其他)变量的顺序和类型是否重要?说,如果Frizzly
定义如下:
typedef struct {
uint16_t b[2];
uint32_t a;
}
在第二个示例中的强制转换之后,b
现在由不兼容 ( uint32_t
) 类型的内存支持。转换是否仍然有效(或者更确切地说,通过转换的指针访问值)?对任一元素的a
更改是否会改变(反之亦然)的第一个元素的值,i
就好像严格别名被禁用一样?
另外,如果上述内容有效,那么如果我有这样的结构怎么办:
typedef struct {
void *m;
uint16_t hooah[4];
} Bar;
如果我是正确的,以下演员将打破别名规则:
void test(char *boo, size_t dee) {
Bar *bar = (Bar *)(boo + dee);
do_other_stuff(bar);
}
我可以通过将单个unsigned char
成员添加到结构中来使强制转换有效吗?换句话说,转换不兼容类型的指针通常会破坏别名规则,但是由于从指向包含类型成员的结构的X
指针转换为指向指针X
是一个例外,因此任何从指向 X 的指针到聚合-Y 的转换都可以只需将 X 类型的(可能是虚拟的)成员添加到 Y 中即可使其有效?
(我实际上并没有在编译器中测试上述代码片段。)
编辑:
我知道我的措辞和示例可能相当糟糕,所以我会尝试重新表述这个问题:如果我理解正确,那么指向结构的指针对类型为“X”的元素数组进行别名是合法的,只要该结构包含“X”类型的成员。现在,当取消引用结构的成员时,该成员是否必须是“X”类型,或者是对结构的所有成员制定的严格别名规则的例外,无论它们的类型如何,只要有一个成员合适的类型?