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
    之前开始,或者
    B2
    的执行应在ass之前结束签字
如果不满足这些要求,则行为未定义


让我们看看关于访问
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)的转换
to
b
定义明确且意义明显,因此程序的行为被定义。此外,由于
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
分隔的子范围中的限制限定符)。