【发布时间】:2014-12-08 09:22:23
【问题描述】:
考虑以下代码:
void doesnt_modify(const int *);
int foo(int *n) {
*n = 42;
doesnt_modify(n);
return *n;
}
doesnt_modify 的定义对编译器不可见。因此,它必须假定doesnt_modify 更改了n 指向的对象,并且必须在return 之前读取*n(最后一行不能被return 42; 替换)。
假设,doesnt_modify 不会修改 *n。我考虑了以下允许优化:
int foo_r(int *n) {
*n = 42;
{ /* New scope is important, I think. */
const int *restrict n_restr = n;
doesnt_modify(n_restr);
return *n_restr;
}
}
这有一个缺点,doesnt_modify 的调用者必须告诉编译器 *n 没有被修改,而不是函数本身可以通过其原型告诉编译器。仅在声明中将restrict 限定为doesnt_modify 的参数是不够的,参见。 “Is top-level volatile or restrict significant [...]?”.
当使用gcc -std=c99 -O3 -S(或具有相同选项的Clang)编译时,所有函数都被编译为等效的程序集,所有函数都从*n重新读取42。
是否允许编译器对
foo_r进行这种优化(用return 42;替换最后一行)?如果没有,是否有(如果可能,可移植)方法告诉编译器doesnt_modify不会修改其参数指向的内容?编译器有没有办法理解和利用?是否有任何函数具有 UB(前提是
doesnt_modify不修改其参数的指针)?
为什么我认为,restrict 可以在这里提供帮助(来自 C11 (n1570) 6.7.3.1 “restrict 的正式定义”,p4 [emph. mine]):
[这里B是foo_r的内部块,P是n_restr,T是const int,X是*n表示的对象,我想想。]
在每次执行
B期间,让L成为基于P具有&L的任何左值。如果L用于访问它指定的对象X的值,并且X也被修改(以任何方式),则适用以下要求:@ 987654362@ 不应是 const 限定的。 […]
$ clang --version
Ubuntu clang version 3.5.0-4ubuntu2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: x86_64-pc-linux-gnu
Gcc 版本是 4.9.2,在 x86 32 位目标上。
【问题讨论】:
-
doesnt_modify2丢弃 const 性并修改指向的对象是合法的,只要对象本身没有声明为const。 -
@T.C.是的,这就是重点。问题是,如果
restrict在这里有什么不同。 -
有趣——你保证没有别的东西给它起别名,而且这个特定的指针不能修改它。我很好奇这意味着什么。
标签: c constants restrict-qualifier