区别如下:
register
是非常局部的优化(即在一个函数内)。寄存器分配是一个相对解决的问题,通过更智能的编译器和更多的寄存器(主要是前者,但说 x86-64 比 x86 有更多的寄存器,并且都有更大的数量,然后说 8 位处理器)
inline
更难,因为它是过程间优化。然而,由于它涉及相对较小的递归深度和少量过程(如果内联过程太大,则没有内联的意义),它可以安全地留给编译器。
restrict
更难。要完全了解这两个指针没有别名,您需要分析整个程序(包括库、系统、插件等) - 甚至会遇到问题。然而,对于程序员来说,信息更清楚,它是规范的一部分。
考虑非常简单的代码:
void my_memcpy(void *dst, const void *src, size_t size) {
for (size_t i = 0; i < size; i++) {
((char *)dst)[i] = ((const char *)str)[i];
}
}
使这段代码高效有什么好处?是的 -memcpy
往往非常有用(比如复制 GC)。这段代码可以向量化吗(这里 - 用文字移动 - 说 128b 而不是 8b)?编译器必须推断出这一点,dst
并且src
不会以任何方式别名,并且它们指向的区域是独立的。size
可能取决于用户输入或运行时行为或其他元素,这使得分析实际上不可能 - 与停止问题类似的问题 - 通常我们无法在不运行它的情况下分析所有内容。或者它可能是 C 库的一部分(我假设是共享库)并且由程序调用,因此所有调用站点在编译时甚至都不知道。如果没有这样的分析,程序将在优化时表现出不同的行为。另一方面,程序员可以通过了解(甚至更高级别的)设计而不是自下而上的分析来确保它们是不同的对象。
restrict
也可以是文档的一部分,因为可能是程序员以无法处理 2 个别名指针的方式编写了该过程。例如,如果我们想从别名位置复制内存,上面的代码是不正确的。
综上所述 - 足够智能的编译器将无法在不了解整个程序的情况下推断出restrict
(除非我们转向理解代码含义的编译器) 。即使那样,它也接近于不可判定性。然而,对于本地优化,编译器已经足够聪明了。我猜想,具有整个程序分析的 Sufficiently Smart Compiler 将能够在许多有趣的情况下进行推断。
PS。本地我的意思是单一功能。所以局部优化不能假设任何关于参数、全局变量等的东西。