【发布时间】:2021-08-08 22:27:03
【问题描述】:
这几天我一直在阅读一些关于严格别名规则的文章。以下是我的理解:
-
对象的有效类型是其声明的类型。如果对象是一个分配的内存,它只有在被具有有效类型的左值访问时才拥有内存,该左值成为对象的有效类型。
-
对对象值的访问必须通过与其有效类型兼容的类型。
在我认为我明白了这个之后,我想做一个简单的实验,看看当我故意违反规则时,我的编译器是否真的警告过这个。这是我的代码:
int main(void) {
unsigned char c[5] = {0x1, 0x2, 0x3, 0x4, 0x5};
int i = *(int*)c;
printf("%x\n", i);
return 0;
}
在我看来,这似乎违反了规则,因为c 的有效类型为char,我们正尝试使用int 指针访问它。
但是我的 gcc 编译得很好!即使使用最高的约束级别 (-Wstrict-aliasing),它也不会发出任何警告。但奇怪的是,将 int 替换为 float 会得到预期的响应:
int main(void) {
unsigned char c[5] = {0x1, 0x2, 0x3, 0x4, 0x5};
float i = *(float*)c;
printf("%f\n", i);
return 0;
}
编译器对此代码给出警告。 (dereferencing type-punned pointer will breakk strict-aliasing rules [Wstrict-aliasing])
第一个代码真的违反规则吗?我知道将任何指针转换为 char* 类型都可以,但反过来是真的吗?还是只是 gcc 不太关心的东西?
【问题讨论】:
-
来自stackoverflow.com/a/98702/1491895:该规则的例外是char*,它允许指向任何类型。
-
但反过来是不是真的 - 不,不是。
char*的严格别名规则例外仅说明任何类型的对象都可以别名为char*- 即对象仍然是原始类型,但可以使用char*访问。正如您所说,在您的情况下,有效类型是char*的数组,因此以int*或float*访问它是违反规则的。编译器应该像您期望的那样警告它,我认为它不是一个遗漏,或者一些特定于实现的事情 - 编译器具有明确定义的行为。 -
顺便说一句,我没有看到任何 sn-ps 的警告(使用固定代码,因为原始代码有错误) - gcc 10.3.0
-
@EugeneSh。我给了
-Wstrict-aliasing和-fstrict-alisasing作为选项。那仍然没有警告吗?如果是这样,那真的很有趣! (我的是 9.3.0) -
gcc 4.8.5 和
-fstrict-alisasing会为两者生成警告。
标签: c gcc language-lawyer strict-aliasing