9

阅读本文我了解到,如果它们具有兼容的成员,您可以对结构进行别名(即不违反标准),即给定以下结构:

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”类型,或者是对结构的所有成员制定的严格别名规则的例外,无论它们的类型如何,只要有一个成员合适的类型?

4

2 回答 2

2

根据ISO/IEC9899/TC2第 6.7.2.1 节第 13 段:

指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然

因此,只要您将结构指针转换为第一个成员的指针类型,它就不应违反严格的别名(在第 6.5 节第 7 节中指定),也可以通过以下方式访问元素

聚合或联合类型,在其成员中包括上述类型之一(递归地包括子聚合或包含联合的成员)

但这仅适用于另一个方向(通过结构指针访问成员,而不是通过成员指针访问结构)

于 2013-06-09T21:35:17.577 回答
-2

您的所有示例都没有违反规则,甚至将 char 数组转换为 struct 指针。
您需要关心的是:

  • 数组足够大
  • 成员对齐
于 2013-06-09T10:53:26.423 回答