【发布时间】:2013-06-09 06:45:10
【问题描述】:
阅读this 我了解到,如果结构具有兼容的成员,即给定以下结构,您可以对结构进行别名(即不违反标准):
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 中就有效?
(我实际上并没有在编译器中测试上面的代码sn-ps。)
编辑:
我知道我的措辞和示例可能相当糟糕,所以我将尝试重新表述这个问题:如果我理解正确,指向结构的指针对类型为“X”的元素数组进行别名是合法的只要结构包含“X”类型的成员。现在,当取消引用结构的成员时,该成员是否必须是“X”类型,或者是为结构的所有成员制定的严格别名规则的例外,无论它们的类型如何只要有一个适当类型的成员?
【问题讨论】:
-
我总是看到人们将两者结合起来并使用它。这样一来,您总能得到两者的最严格版本。
-
如果它编译,它不会违反标准。没有?
-
@basin - 不正确,在任何情况下,技术上的别名要求都与通过指针的访问有关,因此只能在运行时违反(尽管足够聪明的编译器 可能 捕获 一些编译过程中出现这样的问题。)
标签: c alias strict-aliasing