c - `const T *restrict` 能保证指向的对象没有被修改吗?

标签 c constants restrict-qualifier

考虑以下代码:

void doesnt_modify(const int *);

int foo(int *n) {
    *n = 42;
    doesnt_modify(n);
    return *n;
}

定义doesnt_modify的地方对编译器不可见。因此,它必须假定 doesnt_modify更改对象 n指向并必须阅读 *nreturn 之前(最后一行不能用 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没有被修改,而不是函数本身可以通过它的原型(prototype)告诉编译器。简单 restrict - 将参数限定为 doesnt_modify在声明中是不够的,cf。 “Is top-level volatile or restrict significant [...]?” .

使用 gcc -std=c99 -O3 -S 编译时(或具有相同选项的 Clang),所有函数都编译为等效的程序集,全部重新读取 42来自 *n .

  1. 是否允许编译器为 return 42; 执行此优化(用 foo_r 替换最后一行) ?如果没有,是否有一种(可移植的,如果可能的话)告诉编译器的方法 doesnt_modify不修改它的参数指向什么?编译器有没有办法理解和使用?

  2. 是否有任何函数具有 UB(假设 doesnt_modify 不修改其参数的指针对象)?

为什么我认为,restrict可以在这里提供帮助(来自 C11 (n1570) 6.7.3.1“restrict 的正式定义”,p4 [emph.mine]):

[在这种情况下,Bfoo_r 的内部 block , Pn_restr , Tconst int , 和 X是由 *n 表示的对象,我想。]

During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified. […]

$ 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 位目标上。

最佳答案

版本 1 似乎由 restrict (C11 6.7.3.1) 的正式定义明确指定。对于以下代码:

const int *restrict P = n;
doesnt_modify(P);
return *P;

6.7.3.1中使用的符号是:

  • B - 那个代码块
  • P - 变量 P
  • T - *P 的类型,即 const int
  • X - P
  • 指向的(非常量)int
  • L - 左值 *P 是我们感兴趣的

6.7.3.1/4(部分):

During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified [...] If these requirements are not met, then the behavior is undefined.

请注意 T 是 const 限定的。因此,如果在此 block 期间(包括调用该 block 中的函数期间)以任何方式修改了 X,则行为未定义。

因此编译器可以像 doesnt_modify 没有修改 X 一样进行优化。


版本 2 对于编译器来说有点困难。 6.7.6.3/15 表示在原型(prototype)兼容性中不考虑顶级限定符——尽管它们没有被完全忽略。

所以尽管原型(prototype)说:

void doesnt_modify2(const int *restrict p);

仍然可能是函数体声明为 void dont_modify2(const int *p),因此可能会修改 *p

我的结论是,当且仅当编译器可以看到 doesnt_modify2 的定义并确认 p 在定义中被声明为 restrict参数列表,然后它就可以执行优化。

关于c - `const T *restrict` 能保证指向的对象没有被修改吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26346301/

相关文章:

c++ - 为什么我收到错误消息 : "restrict" not allowed?

使用已在当前范围内受到限制的受限参数调用函数

c++ - 将变量定义为自动限制

c - 递归调用的顺序

c - 转义常规字符

c - 为什么不允许使用 const 进行可变大小的对象初始化

c++ - 使用重载后自减运算符时,为什么需要在 << 重载函数中使用 const 引用参数?

c++ - 如何创建动态分配的 const 对象数组,但已为其分配值?

c - 返回语句 C 上的 SegFault

c - 如何用字符串在内存中插入空字节