ars*_*enm 6 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 n)
{
for (unsigned int i = 0; i < m; ++i)
foo(&array[i * n], array2[i], n);
}
Run Code Online (Sandbox Code Playgroud)
这是否打破了bar()中限制的规则,你将数组的一部分地址传递给foo(),即使你真的没有在bar()中使用别名作为数组的一部分?
(所有引文均指N1256,即C99加技术勘误(TC3).)
正式定义restrict见§6.7.3.1.我引用下面最重要的子条款.P是一个restrict限定指向类型T的指针,其范围是一个块B.指针表达式E被认为是基于 P它是否取决于它P自身的值,而不是P指向的值.
在每次执行期间
B,L设为任何&L基于P的左值.如果L用于访问X它指定的对象的值,并且X也被修改(通过任何方式),则以下要求适用:
T不得具有合格资格.- 用于访问值的每个其他左值
X也应该具有基于的地址P.- 出于本子条款的目的,每次修改的访问也
X应被视为修改P.- 如果
P指定了一个指针表达式的值,该指针表达式E基于P2与块相关联的另一个受限指针对象,B2那么执行B2应该在执行之前开始B,或者执行B2应该在赋值之前结束.如果不满足这些要求,则行为未定义.
让我们来看看什么规则不得不说访问的部分bar的array在foo.我们首先array在参数列表中声明一个限制限定的指针bar.为清楚起见,我将alpha转换参数foo:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
Run Code Online (Sandbox Code Playgroud)
指向的存储array也通过修改b.对于第二个要点而言,这&array[i*n]是可以的array+(i*n)(参见§6.5.3.2).
如果b是限制合格的话,那么我们必须用P← b,B← foo,P2← array,B2← 检查第四个子弹点bar.由于B嵌套在内部B2(函数的行为就像在此处内联,参见§6.7.3.1.11),因此满足第一个条件.还有一个第三个子弹点(对b[i]in 的访问foo)的实例,这不是问题.
但是b不受限制.根据§6.3.2.3.2,"对于任何限定符q,指向非q限定类型的指针可以转换为指向该类型的q-限定版本的指针; 存储在原始和转换指针中的值应比较相等".因此,从转换array+(i*n)到b是明确的,具有明显的意义,所以程序的行为被定义.此外,由于b不restrict-qualified,它不需要服从任何线性条件.例如,以下foo内容与以下内容合法bar:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
Run Code Online (Sandbox Code Playgroud)
增加:为了解决您在特定问题"在bar()中将数组的一部分的地址传递给foo()",这是一个非问题:restrict适用于指针,而不是数组,并且您可以执行算术运算它(子弹点2).
| 归档时间: |
|
| 查看次数: |
1811 次 |
| 最近记录: |