关于C语言restrict限定指针的标准合规性及术语疑问
依据C11 6.7.3.1条款内容:
1 设D为普通标识符的声明,该声明指定对象P为指向类型T的restrict限定指针。
2 若D出现在块内且无extern存储类,令B表示该块;若D出现在函数定义的参数声明列表中,令B表示关联的块;否则,令B表示main函数的块(或独立环境中程序启动时调用的任意函数的块)。
3 在下文中,若在B执行期间、E求值之前的某个序列点修改P,使其指向原指向数组对象的副本会改变E的值,则称指针表达式E基于对象P137)。注意“基于”仅针对指针类型的表达式定义。
4 在B的每次执行期间,设L为任意左值,且&L基于P。若L用于访问其指定的对象X的值,且X也被(以任何方式)修改,则需满足以下要求:T不应是const限定的。所有其他用于访问X值的左值,其地址也应基于P。就本小节而言,修改X的每次访问都应视为也修改了P……
137) 换句话说,E依赖于P本身的值,而非通过P间接引用的对象的值。例如,若标识符p的类型为(int **restrict),则指针表达式p和p+1基于p指定的restricted指针对象,但指针表达式*p和p[1]则不基于该对象。
测试代码:
int main() { int A = 5; int* restrict P; P = &A; *P = 10; int *N = P; *N = 20; }
问题解答:
你的代码严格符合C11标准,不存在未定义行为。N是从P复制得到的指针,所有访问A(即条款中的X)的左值(*P和*N)的地址都基于P,完全满足6.7.3.1第4款的约束要求。
针对你对**“就本小节而言,修改X的每次访问都应视为也修改了P”**这句话的疑问,核心要点如下:
- 这句话不是说修改X(指针指向的对象)会真的改变P这个指针对象的存储值——你的代码里
P始终指向A,值从未变化。 - 它是C标准为了明确restrict规则的判定逻辑而补充的说明:在判断指针表达式是否“基于”P时,要把所有修改X的操作,看作是对P本身进行了修改。这样可以避免规则漏洞,确保restrict的约束能覆盖所有涉及X修改的场景。
- 举个具体的判定场景:如果在修改X之后,有一个指针表达式E需要判断是否基于P,那么根据这个规则,我们要假设P被修改过,再看E的值是否会因此改变。在你的代码中,
N是在修改X之前从P复制的,所以这个规则不会影响N的合法性。
简单说,这句话是规则的补全,用来明确restrict约束的适用范围,而非字面意义上的“修改指向对象等于修改指针”。
内容的提问来源于stack exchange,提问作者user24723440

