【发布时间】:2019-02-23 22:51:22
【问题描述】:
考虑以下函数:
int bar(const int* __restrict x, void g())
{
int result = *x;
g();
result += *x;
return result;
}
由于调用g(),我们是否需要从x 读取两次?或者__restriction 是否足以保证g() 的调用不会访问/不会更改地址x 处的值?
在this link,我们看到最流行的编译器不得不说这个(GodBolt;语言标准 C99,平台 AMD64):
- clang 7.0:遵守限制。
- GCC 8.3:没有限制。
- MSVC 19.16:没有限制。
clang 是否正确地优化了第二次读取,不是吗?我在这里询问 C 和 C++,因为行为是相同的(感谢@PSkocik)。
相关信息和一些注释:
- 不熟悉
__restrict(或__restrict__)的读者不妨看看:What does the restrict keyword mean in C++? - GCC 在 C++ 中的 documentation page on restricted pointers。
- 我在这一点上打开了bug against GCC。
-
x被标记为const的事实在这里并不重要 - 如果我们删除const并且问题保持不变,我们会得到相同的行为。
【问题讨论】:
-
为什么不标记它[c]?这是这个问题的合法标签(可能比 C++ 标签更合法),你会得到更多的眼球。
-
@PSkocik:在看到您的 GodBolt 示例后 - 进行相应的编辑。
-
为了对
g()进行适当的优化,编译器必须确定它会注意到任何可能导致x的地址在运行期间暴露给外界的操作bar的执行。在这种情况下,显然没有这样的动作,但是除非编译器能够注意到所有这样的动作,否则最好假设引用可能已经泄漏,而实际上它没有泄漏,而不是假装它不会泄漏。它有。 -
@supercat:如果我们不使用
restrict,你说的是真的。如果我们这样做,编译器不必确定这一点,它需要“相信我的话”。 -
@einpoklum:函数
g()将被允许访问与*x相同的存储,当且仅当它使用基于x的指针(而不仅仅是@987654343 所在的指针@是基于)这样做。如果编译器不可能合法地接收到这样的指针,则编译器只能假定g()无法访问*x。在没有__restrict的情况下,编译器必须考虑到在调用bar之前地址可能已经暴露给外部代码的可能性。
标签: c gcc visual-c++ clang restrict