【问题标题】:Is this an invalid use of restrict pointers?这是对限制指针的无效使用吗?
【发布时间】:2010-10-04 16:19:12
【问题描述】:

假设我有一个大数组,我计算一个索引并传递给第二个函数。举个简单的例子,比如:

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() 中为数组的一部分使用别名?

【问题讨论】:

    标签: c c99 restrict-qualifier


    【解决方案1】:

    (所有引用参考N1256,即C99加技术勘误(TC3)。)

    restrict 的正式定义在 §6.7.3.1 中给出。我引用下面最重要的子条款。 P 是一个restrict 限定指针,指向类型T,其范围是一个块B。如果指针表达式E 依赖于P 本身的值,而不是P 指向的值,则称它基于 P

    在每次执行B 期间,让L 为基于P 的具有&amp;L 的任何左值。如果L 用于访问它指定的对象X 的值,则@987654336 @ 也被修改(以任何方式),则适用以下要求:

    • T 不应是 const 限定的。
    • 用于访问X 值的每个其他左值也应具有基于P 的地址。
    • 就本子条款而言,修改X 的每个访问都应视为修改P
    • 如果P 分配了一个指针表达式E 的值,该表达式基于另一个受限指针对象P2,与块B2 关联,则B2 的执行应在执行之前开始B 的执行,或B2 的执行应在分配之前结束。

    如果不满足这些要求,则行为未定义。


    让我们看看规则对访问bar 中的array 的部分foo 有什么规定。我们从array 开始,这是一个在bar 的参数列表中声明的限制限定指针。为了清楚起见,我将对foo的参数进行alpha转换:

    void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
    

    array指向的存储也是通过b修改的。第二个要点没关系,因为&amp;array[i*n] 等同于array+(i*n)(请参阅第 6.5.3.2 节)。

    如果 b 是受限制的,那么我们必须检查第四个要点:P​←bB​←foo、@987654365 @​←arrayB2​←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 合格的,它不需要遵守任何线性条件。例如,以下foobar 组合是合法的:

    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)。

    【讨论】:

    • 我不知道你说的是对还是错,但是完全部署标准的道具。
    • @Matt:代码是正确的(部分是因为限制规则在这里没有做太多,部分是因为您可以转换由foo 分隔的子作用域中的限制限定符)。
    【解决方案2】:

    不,restrict 意味着数组不能为任何东西加上别名,所以你可以在不违反规则的情况下将东西传递给 bar

    【讨论】:

    • 我认为这个问题需要引用标准,而不是像“限制手段......”这样的随意解释。 C99 别名规则太复杂了,不能依赖这样的随意解释。
    • restrict 的规则非常简单,除了restrict 指针外其他任何东西都无法访问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-19
    相关资源
    最近更新 更多