14.6 Strict Aliasing

restrict 被引入之前,程序员有时使用不同的结构体名字来获取到相同的效果。编译器看到数据类型不同进而推断这些指针不能指向相同的数据(这个规则一般被称为 strict aliasing 严格别名规则)。

这种规则存在这样一些假设:

  • 指向不同内置类型的指针不会是别名。
  • 指向有不同 tag 的结构体或 union 结构的指针不会互为别名(所以 struct foo 和 struct bar 不会混用并指向对方)。
  • 使用 typedef 创建的类型别名可能指向相同的数据。
  • char * 类型(signed 或者 unsigned)是一个特例。编译器始终假设 char* 可以是其它类型的别名,但是反过来不成立。也就是说我们可以创建一个 char buffer,使用这个 char buffer 来获取一些数据,然后将它作为一个结构体的实例的别名。

破坏这些规则就可能会引起难查的优化 bug,因为这样会触发未定义行为。

列表 14-18 中的例子,可以在不使用 restrict 关键字的前提下获得与 restrict 关键字一样的效果。也就是使用 strict aliasing 来达到我们的目的,把两个参数打包到具有不同的 tag 的 struct 中去。

列表 14-23 展示了修改后的源码。

Listing 14-23.restrict-hack.c

struct a {
    int v;
};

struct b {

int v;
};

void f(struct a* x, struct b* add) {

    x->v += add->v;
    x->v += add->v;
}

结果令我们很满意,编译器把读取优化掉了。列表 14-24 展示了反编译的结果。

Listing 14-24.restrict-hack-dump

0000000000000000 <f>:
   0:   8b 06                     mov   eax,DWORD PTR [rsi]
   2:   01 c0                     add   eax,eax
   4:   01 07                     add   DWORD PTR [rdi],eax
   6:   c3                        ret

我们不鼓励在 C99 或更新的标准下写的代码使用上述 aliasing 规则,因为 restrict 显然更加一目了然,并且也不会引入没什么必要的类型名。

results matching ""

    No results matching ""