C99/C11 中的两个结构可以别名吗?

Dan*_*sko 3 c strict-aliasing

假设我们有两个结构体

struct hello {  
  float a;
  float b;
};
Run Code Online (Sandbox Code Playgroud)

struct world {
  float c;
  float d;
};
Run Code Online (Sandbox Code Playgroud)

和一个函数

void func(struct hello* h, struct world* w);
Run Code Online (Sandbox Code Playgroud)

这两个参数是否可以别名,因为它们都包含float,因此编译器必须生成确保正确性的代码?如果我确定w并且h不存储在相同的内存位置(或不以任何方式重叠),我是否可以通过将函数更改为以下内容来实现加速?

void func(struct hello *restrict h, struct world *restrict w);
Run Code Online (Sandbox Code Playgroud)

此外,原始类型 offloat对此有任何影响还是相同的规则适用于int?

Lun*_*din 6

您的示例非常接近于创建两个兼容类型(C11 6.2.7)的结构。但是为了兼容,它们必须具有相同的成员同名,并且struct标签也必须相同。

你没有那个,所以 (TL;DR) 问题中的结构不能别名。

然而,人们可以玩的另一件事是一种称为公共初始序列(C11 6.5.2.3)的技巧,您可以将两个结构放在一个联合中,这在翻译单元中是可见的。然后,您将被允许检查每个结构类型的第一个成员序列,直到它们停止兼容为止。你可以这样做:

typedef union
{
  struct hello h;
  struct world w;
} hack_t;
Run Code Online (Sandbox Code Playgroud)

然后访问任一结构的单个成员。不幸的是,这条规则有点奇怪,显然编译器并不总是很好地支持它——该规则受某些缺陷报告 (DR) 的约束。我不确定它在当前 C17 中的状态。

但是不管那个技巧,联合仍然可以通过 a左值访问 astruct hello或 a ,因为它是一个联合类型,在其成员之间包含一个兼容类型(C11 6.5/7)。我想有点用。struct worldhack_t

除了这些情况之外,您不能将指针类型从一种指针类型疯狂地转换为另一种指针类型并取消引用。即使所有单个成员都是兼容类型,这也将是严格的别名违规(C11 6.5/7)。(当然,您可以float通过取消引用float指向该成员的指针来访问任何单个成员。)

您的restrict优化不适用,因为结构不能别名,除非它们是真正兼容的类型。所以编译器会假设它们总是在不同的内存区域。

无论您使用float或任何其他原始数据类型,它们的行为都相同,但字符类型除外。指向字符类型的指针可用于访问任何数据而不会出现严格的别名冲突(但不是相反,通过另一个不兼容的类型读取字符类型)。