函数的限制限定指针参数是否允许优化调用者函数?

log*_*536 7 c compiler-optimization language-lawyer restrict-qualifier

函数的限制限定指针参数是允许编译器优化该函数的有效方法:

int f(const int *restrict p) {
  int n=*p;
  printf("Debug\n");
  return *p==n;
}
Run Code Online (Sandbox Code Playgroud)

这里带有 -O3 的 Clang 17 将只返回 1 ,而不重新检查*p,也不执行比较。如果没有restrict*p则必须重新检查并进行比较。这是因为printf是一个外部函数,编译器不知道它是否会修改*p. 事实上,如果p碰巧指向 的文件位置指示器stdoutprintf实际上会修改它。

因此,作为一般原则,如果您希望对函数进行最大程度的优化,并且您的函数曾经调用外部函数,那么声明所有参数并不是没有意义的restrict。当然,这对调用者施加了严格的限制,因为它要求他们承诺不会使用别名到意外位置的指针来调用您的函数。

我的问题比这个观察更进一步。我问是否也restrict允许优化您的函数的调用者

int f(const int *restrict p);
int caller(int *p) {
  int n=*p;
  f(p);
  return *p==n;
}
Run Code Online (Sandbox Code Playgroud)

在我看来,这保证了编译器f不会修改*p,因此它可以省略重新检查*p和比较,并且可以安全地返回 1。Clang 和 GCC 都没有进行此优化。

我知道他们不优化调用者是可以的。我问是否允许优化。(这主要是关于我的程序的语义的问题,而不是关于性能的问题。)

Eri*_*hil 5

在此代码中:

\n
int f(const int *restrict p);\nint caller(int *p) {\n  int n=*p;\n  f(p);\n  return *p==n;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

编译器无法得出*p在执行期间不会改变的结论f,因为下面的代码显示了定义f和调用,caller其中定义了行为(不违反要求),但执行期间restrict值发生了变化:*pf

\n
extern int m[2];\n\nint f(const int * restrict p)\n{\n    m[0] = 3;\n    return p[1];\n}\n\nvoid bar(void)\n{\n    caller(m);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,当f被调用时,p指向m[0],因此*p也是m[0]。由于f发生变化m[0], 的值*p在 执行期间发生变化f,但这并不违反restrict要求,因为restrict定义仅在p直接或间接使用 来访问对象时强加要求。C 2018 6.7.3.1 4 说:

\n
\n

在 的每次执行期间B,令为基于 的L任何左值。如果用于访问它指定的对象的值,并且也被修改(通过任何方式),则以下要求适用:\xe2\x80\xa6&LPLXX

\n
\n

在上面fm[0]仅通过左值访问m[0],而不是通过地址基于 的任何左值访问p。因此 的先决条件restrict永远不会出现,因此它对是否或如何修改m[0]没有任何限制。m[0]

\n