这是限制指针的无效使用吗?
假设我有一个大数组,我计算索引并将其传递给第二个函数。举一个简单的例子,例如:
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);
}
这是否违反了 bar() 中的限制规则,其中您将数组的一部分的地址传递给 foo(),即使您从未真正在 bar 中的数组的一部分使用别名()?
Suppose I have large array which I calculate an index into and pass to a second function. As a simple example, something like:
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);
}
Is this breaking the rules for restrict in bar() where you pass the address of part of the array to foo(), even if you never really use the alias for a part of the array within bar()?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
(所有引用均参考 N1256,即C99 加上技术勘误 (TC3)。)
restrict
的正式定义在 §6.7.3.1 中给出。我引用下面最重要的条款。P
是一个restrict
限定的指针,指向类型T
,其范围是块B
。如果指针表达式E
取决于P
本身的值,则称其基于P
,而不是P
指向的值。让我们看看规则对于访问
foo
中bar
的array
部分有什么规定。我们从array
开始,它是在bar
的参数列表中声明的限制限定指针。为了清楚起见,我将对foo
的参数进行 alpha 转换:array
指向的存储也通过b
进行修改。第二个要点没问题,因为&array[i*n]
相当于array+(i*n)
(参见第 6.5.3.2 节)。如果
b
是限制限定的,那么我们必须使用P
←b
检查第四个要点,B
←foo
,P2
←数组
,B2
←bar< /代码>。由于
B
嵌套在B2
内(此处函数的行为如同内联,请参阅第 6.7.3.1.11 节),因此满足第一个条件。还有第三个要点的一个实例(在foo
中访问b[i]
),这不是问题。但是
b
没有限制条件。根据第 6.3.2.3.2 节,“对于任何限定符 q,指向非 q 限定类型的指针可以转换为指向 q-类型的限定版本;原始指针和转换后指针中存储的值应相等”。因此从array+(i*n)
到b
的转换是明确定义的并且具有明显的含义,因此程序的行为被定义。此外,由于b
不是restrict
限定的,因此它不需要遵守任何线性条件。例如,以下foo
与bar
结合使用是合法的:ADDED:为了解决您的特定问题“在 bar() 中传递数组的一部分的地址到 foo()”,这不是问题:
restrict
适用于指针,而不是数组,并且您可以对其执行算术(要点 2)。(All citations refer to N1256, which is C99 plus technical corrigenda (TC3).)
The formal definition of
restrict
is given in §6.7.3.1. I quote the most important subclause below.P
is arestrict
-qualified pointer to typeT
whose scope is a blockB
. A pointer expressionE
is said to be based onP
if it depends on the value ofP
itself, not the value thatP
points to.Let's look at what the rules have to say about accesses to parts of
bar
'sarray
infoo
. We start witharray
, a restrict-qualified pointer declared in the parameter list ofbar
. For clarity, I will alpha-convert the parameters offoo
:The storage pointed to by
array
is also modified throughb
. That's ok with the second bullet point as&array[i*n]
is equivalent toarray+(i*n)
(see §6.5.3.2).If
b
was restrict-qualified, then we would have to check the fourth bullet point withP
←b
,B
←foo
,P2
←array
,B2
←bar
. SinceB
is nested insideB2
(functions behave as if inlined here, see §6.7.3.1.11), the first condition is met. There is also one instanciation of the third bullet point (the access tob[i]
infoo
) which is not a problem.However
b
is not restrict-qualified. According to §6.3.2.3.2, “For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal”. Therefore the conversion fromarray+(i*n)
tob
is well-defined and has the obvious meaning, so the program's behavior is defined. Furthermore, sinceb
is notrestrict
-qualified, it doesn't need to obey any linearity condition. For example, the followingfoo
is legal in combination withbar
:ADDED: To address your specific concern “in bar() where you pass the address of part of the array to foo()”, this is a non-issue:
restrict
applies to the pointer, not the array, and you can perform arithmetic on it (bullet point 2).不,restrict 意味着 array 不能给任何东西起别名,所以你可以将东西传递给 bar 而不会违反规则
No, restrict means that array can't alias anything, so you can pass stuff to bar without breaking the rules