【问题标题】:Is it dangerous to call a function and pass it a restrict-qualified pointer?调用函数并向其传递限制限定的指针是否危险?
【发布时间】:2012-10-06 15:06:30
【问题描述】:

考虑这两个函数:

void foo(char * __restrict localPtr)
{
    // some work with localPtr
}

void bar(char * __restrict ptr)
{
    // some work with ptr
    foo(_ptr);
    // some other work with ptr
}

由于ptr 已在bar 中声明为__restrict,调用foo() 危险吗?危险是指localPtr 指向的内存区域与ptr 的内存区域重叠。对此有何指导方针?

【问题讨论】:

  • Isn' restrict 仅对 多个 指针参数有用还是我记错了?

标签: c++ restrict-qualifier


【解决方案1】:

restrict 限定符意味着被调用函数访问localPtrfoo 中传递的内存的唯一方法是通过该指针;那段记忆没有别名。这可能使优化器能够生成更好的代码,因为它不必担心另一个指针也会改变数据。

在这种情况下,以及在大多数其他情况下,restrict 限定符使您(进行调用的程序员)有责任确保您遵守“无别名”要求。

上面的代码没有明显的危险。

请注意,大多数情况下,当使用restrict 时,参数列表中有多个指针。从C标准,比较:

void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);

第一个(memcpy())表示内存块[s1 .. s1+n-1][s2 .. s2+n-1]不能重叠;如果它们实际上重叠,您将获得未定义的行为。第二个 (memmove()) 没有强制要求。


但是对foo() 的调用不是创建了另一个改变数据的指针吗?

是的,不,有点……但大多不是。

foo() 中的指针肯定会传递给bar(),但是当bar() 运行时,bar() 获取内存的唯一方法是通过它传递的指针。因此,bar() 能够在假设它正在使用的内存没有别名的情况下进行编译。

当编译器处理foo() 时,它知道(确保)在评估bar() 的参数之后和调用函数之前存在一个序列点,并且在函数返回时还有另一个。它知道数据可能已被bar() 修改,因为它没有传递const char *。因此,它将生成代码来解释这些可能性。但是,编译器也知道foo() 可以访问由localPtr 寻址的内存的唯一方法是通过localPtr(这就是restrict 所说的),并且它可以基于该假设继续进行。

因此,在调用bar() 时,存在指针的第二个副本,但它并没有以任何方式违反restrict 的规则。

【讨论】:

  • 但是对foo的调用不是创建了另一个改变数据的指针吗?
  • 好的。我害怕的是下面的场景:foo() 的开头,*ptr 的内容存储在一个寄存器中。然后调用bar() 并修改*ptr。当bar() 返回时,foo() 使用寄存器而不是再次获取*ptr,因为foo() 确定只有ptr 可以修改该区域。
  • 这个序列可能会发生;编译器必须确保它不会影响其操作。 restrict 并没有真正影响这一点。如果编译器在函数调用后使用了寄存器值,则编译器优化错误(又名“编译器错误”)。如果bar() 被定义为void bar(const char * restrict data),那么优化将是合法的,但bar() 将不得不打破const char * 的承诺才能影响事情。但是通过抛弃const 然后更改它指向的数据,修改后的bar() 正在调用未定义的行为;任何事情都会发生。
  • @JonathanLeffler:如果识别的对象实际上是 const 合格,则抛弃 const 只是 UB。实现基于const 的最大优化将需要有几种不同风格的关键字来做出不同的承诺,标准定义的形式是最松散的(使指针的“常量”成为句法而不是语义特征)。其他形式将是“const”指针的变体,接收者将承诺永远不会直接写入或导致被写入,以及承诺多次观察到的数据的变体......
  • ...每次观察时都会出现相同的情况。这样的事情将允许非常有用的优化,但标准不承认任何这样的概念。
猜你喜欢
  • 2016-07-19
  • 1970-01-01
  • 2018-09-15
  • 2017-05-19
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多