C 这是限制指针的无效使用吗?
假设我有一个大数组,我计算一个索引并将其传递给第二个函数。作为一个简单的例子,如下所示:C 这是限制指针的无效使用吗?,c,c99,restrict-qualifier,C,C99,Restrict Qualifier,假设我有一个大数组,我计算一个索引并将其传递给第二个函数。作为一个简单的例子,如下所示: void foo(float* array, float c, unsigned int n) { for (unsigned int i = 0; i < n; ++i) array[i] *= c; } void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int
void foo(float* array, float c, unsigned int n)
{
for (unsigned int i = 0; i < n; ++i)
array[i] *= c;
}
void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
for (unsigned int i = 0; i < m; ++i)
foo(&array[i * n], array2[i], n);
}
void foo(浮点*数组、浮点c、无符号整数n)
{
for(无符号整数i=0;i
这是否违反了在bar()中将部分数组的地址传递给foo()的restrict的规则,即使您从未在bar()中为数组的一部分使用过别名?不,restrict意味着数组不能对任何内容使用别名,因此您可以在不违反规则的情况下将内容传递给bar(所有引用均参考C99加技术勘误表(TC3)。)
restrict
的正式定义在§6.7.3.1中给出。我引用了下面最重要的子条款。p
是一个restrict
类型的限定指针,其范围为块B
。如果指针表达式E
取决于p
,则称其为基于p
P本身,而不是P
指向的值
在每次执行B
期间,让L
成为基于p的&L
的任何左值。如果使用L
访问它指定的对象X
的值,并且X
也被修改(通过任何方式),则以下要求适用:
不应是合格的T
- 用于访问
值的每个其他左值也应具有基于X
的地址P
- 就本款而言,修改
的每次访问也应视为修改X
P
- 如果为
分配了指针表达式P
的值,该值基于与块E
相关联的另一个受限指针对象B2
,则P2
的执行应在执行B2
之前开始,或者B
的执行应在ass之前结束签字B2
让我们看看关于访问
foo
中bar
的array
部分的规则是怎么说的。我们从array
开始,它是在bar
的参数列表中声明的限制限定指针。为了清楚起见,我将对foo
的参数进行α转换:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
array
指向的存储也可以通过b
进行修改。第二个要点是,这没关系。array[i*n]
相当于array+(i*n)
(参见§6.5.3.2)
如果b
符合限制条件,那么我们必须用p
←<代码>b,b
←<代码>foo,P2
←<代码>数组,B2
←<代码>条形图。由于B
嵌套在B2
中(函数的行为就像是内联的,请参见§6.7.3.1.11),因此满足了第一个条件。第三个要点还有一个实例(在foo
中访问B[i]
),这不是问题
但是b
不是限制限定的。根据§6.3.2.3.2,“对于任何限定符q,指向非q限定类型的指针可以转换为指向该类型的q限定版本的指针;原始指针和转换指针中存储的值应相等”。因此,从数组+(i*n)的转换
tob
定义明确且意义明显,因此程序的行为被定义。此外,由于b
不符合restrict
-限定条件,它不需要遵守任何线性条件。例如,以下foo
与bar
组合使用是合法的:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
添加了:为了解决您的具体问题,“在bar()中,您将数组的一部分的地址传递给foo()”,这不是一个问题:
restrict
应用于指针,而不是数组,您可以对其执行算术运算(要点2).我认为这个问题需要引用标准,而不是按照“限制手段…”的思路随意解释.C99别名规则太复杂,无法依赖像那样的随意解释。限制的规则非常简单,除了限制指针之外,无法通过任何东西访问。我无法判断你说的是对是错,但这是完全部署标准的道具。@Matt:代码是正确的(部分原因是限制规则在这里没有什么作用,部分原因是您可以转换掉由foo
分隔的子范围中的限制限定符)。