`const T *restrict` 是否保证指向的对象不被修改? [英] Does `const T *restrict` guarantee the object pointed-to isn’t modified?

查看:22
本文介绍了`const T *restrict` 是否保证指向的对象不被修改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

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;代替).

where the definition of doesnt_modify isn’t visible for the compiler. Thus, it must assume, that doesnt_modify changes the object n points to and must read *n before the return (the last line cannot be replaced by return 42;).

假设,doesnt_modify 不修改 *n.我考虑了以下允许优化:

Assume, doesnt_modify doesn’t modify *n. I thought about the following to allow the optimization:

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 是不够的,参见.是顶级volatilerestrict 重要 [...]?".

This has the drawback that the caller of doesnt_modify has to tell the compiler *n isn’t modified, rather than that the function itself could tell the compiler via its prototype. Simply restrict-qualifying the parameter to doesnt_modify in the declaration doesn’t suffice, cf. "Is top-level volatile or restrict significant [...]?".

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

When compiling with gcc -std=c99 -O3 -S (or Clang with the same options), all functions are compiled to equivalent assembly, all re-reading the 42 from *n.

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

  1. Would a compiler be allowed to do this optimization (replace the last line by return 42;) for foo_r? If not, is there a (portable, if possible) way to tell the compiler doesnt_modify doesn’t modify what its argument points to? Is there a way compilers do understand and make use of?

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

Does any function have UB (provided doesnt_modify doesn’t modify its argument’s pointee)?

为什么我认为,restrict 在这里可以提供帮助(来自 C11 (n1570) 6.7.3.1 Formal definition of restrict",p4 [emph. mine]):

Why I think, restrict could help here (From C11 (n1570) 6.7.3.1 "Formal definition of restrict", p4 [emph. mine]):

[在这种情况下,Bfoo_r的内部块,Pn_restrTconst intX*n表示的对象,我想.]

[In this case, B is the inner block of foo_r, P is n_restr, T is const int, and X is the object denoted by *n, I think.]

B的每次执行过程中,令L为基于P&L的任意左值.如果 L 用于访问它指定的对象 X 的值,并且 X 也被修改(以任何方式),则适用以下要求:T 不得为 const-qualified.[…]

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

Gcc version is 4.9.2, on an x86 32bit target.

推荐答案

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

Version 1 seems clearly specified by the formal definition of restrict (C11 6.7.3.1). For the following code:

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

6.7.3.1 中使用的符号是:

the symbols used in 6.7.3.1 are:

  • B - 代码块
  • P - 变量 P
  • T - *P 的类型,即 const int
  • X - P
  • 指向的(非常量)int
  • L - 我们感兴趣的是左值 *P
  • B - that block of code
  • P - the variable P
  • T - the type of *P which is const int
  • X - the (non-const) int being pointed to by P
  • L - the lvalue *P is what we're interested in

6.7.3.1/4(部分):

6.7.3.1/4 (partial):

B的每次执行过程中,令L为基于P&L的任意左值.如果 L 用于访问它指定的对象 X 的值,并且 X 也被修改(通过任何方式),那么以下要求适用:T 不得为 const 限定[...]如果不满足这些要求,则行为未定义.

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 限定的.因此,如果 X 在此块期间以任何方式被修改(包括在调用该块中的函数期间),则行为未定义.

Note that T is const-qualified. Therefore, if X is modified in any way during this block (which includes during the call to a function in that block), the behaviour is undefined.

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

Therefore the compiler can optimize as if doesnt_modify did not modify X.

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

Version 2 is a bit more difficult for the compiler. 6.7.6.3/15 says that top-level qualifiers are not considered in prototype compatibility -- although they aren't ignored completely.

所以虽然原型说:

void doesnt_modify2(const int *restrict p);

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

it could still be that the body of the function is declared as void doesnt_modify2(const int *p) and therefore might modify *p.

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

My conclusion is that if and only if the compiler can see the definition for doesnt_modify2 and confirm that p is declared restrict in the definition's parameter list then it would be able to perform the optimization.

这篇关于`const T *restrict` 是否保证指向的对象不被修改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆