考虑以下功能:
int bar(const int* __restrict x, void g())
{
int result = *x;
g();
result += *x;
return result;
}
由于调用了x
,我们是否需要从g()
读取两次?还是__restrict
足以保证对g()
的调用不会访问/不会更改地址x
上的值?
在this link,我们看到最流行的编译器不得不对此发表评论(GodBolt;语言标准C99,平台AMD64):
clang是否正确地优化了秒读,不是吗?我在这里同时要求C和C ++,因为行为是相同的(感谢@PSkocik)。
相关信息和一些注意事项:
__restrict
(或__restrict__
)的读者可能想看看:What does the restrict keyword mean in C++? x
被标记为const
的事实在这里并不重要-如果我们放下const
并且问题依旧,我们将得到相同的行为。答案 0 :(得分:0)
我认为这实际上是一个C问题,因为C实际上是带有restrict
并附带正式规范的语言。
控制restrict
使用的C标准部分为6.7.3.1:
1设D为提供一个 将对象P指定为限制限定的指针的方法 输入T。
2如果D出现在块内并且没有存储类extern, 令B代表方块。如果D出现在参数列表中 函数定义的声明,让B表示关联的 块。否则,让B代表main的区块(或 独立运行程序时调用的任何功能 环境)。
3接下来,将指针表达式E称为基于 对象P如果(在执行B之前的某个顺序点 E)的评估,修改P以指向数组对象的副本 它先前指向的位置会更改E.137的值) 只能为具有指针类型的表达式定义“基于”。
4在每次执行B期间,令L为具有&L的任何左值。 P。如果使用L来访问对象X的值,则表示它 指定,并且X也被修改(通过任何方式),则以下内容 适用要求:T不得为const限定的。每隔一个左值 用于访问X值的地址也应基于P。 每次修改X的访问也应被视为修改P,因为 本节的目的。如果为P分配了a的值 基于另一个受限指针的指针表达式E 与块B2关联的对象P2,然后执行B2 应在执行B之前开始,或者B2的执行应开始 在分配之前结束。如果不满足这些要求,那么 行为是不确定的。
5此处执行B表示执行B的那一部分 与标量对象的生存期相对应的程序 B的类型和自动存储期限。
按照我的理解,g()
的执行属于bar
块的执行,因此不允许g()
修改*x
和{{ 1}} 是来优化第二个负载的权利(IOW,如果clang
引用非常量全局变量,*x
不得修改该全局变量。)