【问题标题】:Why is the __restrict__ modifier not enforced?为什么不强制使用 __restrict__ 修饰符?
【发布时间】:2020-04-21 20:03:03
【问题描述】:

如果一个函数参数被注释const int &x 并且我尝试在函数体中执行x++,我会收到一个用于修改只读引用的编译时错误。但是如果我像这样使用__restrict__ 修饰符:

void foo(int & __restrict__ a, int & __restrict__ b) {
    if (a == 1)
        b = 2;
    if (a == 2)
        b = 3;
}

int main() {
    int x = 1;
    foo(x, x); // should be illegal?
    cout << x;
}

...我没有收到编译时错误。如果我在未优化的情况下运行此代码,则输出为3,但如果我使用-O1 或更高版本运行它,则输出为2。似乎检测x 被通过两次会很简单,也很容易被禁止。为什么 C++ 可以防止对 const 的不当使用,但对__restrict__ 的不当使用却没有?

【问题讨论】:

  • 这是未定义的行为。我只是不确定是否可以发布答案,因为我很难找到 C++ 的正确参考
  • 请注意,C++ 并没有对__restrict__任何事情,因为它是一个实现扩展。

标签: c++ pass-by-reference restrict-qualifier


【解决方案1】:

您正在向后看__restrict__

__restrict__ 是一个实现扩展,程序员可以使用它来表示意图,以最大限度地提高生成的代码质量和性能(“优化”)。

这不是检查,也不是对程序的附加约束。

它不是类型系统的一部分,所以它不是函数类型的一部分,所以它不能在调用点(通常)强制执行。

就像其他一些扩展名(例如__builtin_unreachable),用来告诉编译器一些事情。

在这种情况下,您是在告诉它“我不是通过任何其他指针来引用指针”。

您不是在问它“请阻止我通过任何其他指针引用指针”。

C 和 C++ 编译器已经尽可能地执行强大的“别名”检查。在自动混叠检测无法工作的情况下(例如,翻译单元边界)。由于自动别名检测无法工作,__restrict__ 无法强制执行。

而且,即使可以,这也与修饰符的目的相反。

【讨论】:

    【解决方案2】:

    在非常一般的情况下,不可能在编译时诊断它。作为一个简单的反例,请考虑:

     void foo(int* __restrict__ a, int * __restrict__ b);
    
     int x;
     int y;
     std::cin >> x >> y;
     int* a = (x%2) ? &x : &y;
     int* b = (y%2) ? &x : &y;
     foo(a,b);
    

    编译器无法知道ab 是否会指向同一个int。实际上,如果编译器可以进行这样的分析,就不需要__restrict__ 限定符,因为这样编译器就可以自己判断两个指针是否用于访问相同的内存。

    【讨论】:

      【解决方案3】:

      一般来说,检测restrict 违规并不容易。假设你有一个函数

      void bar(int* p1, int* p2) {
          foo(*p1, *p2);
      }
      

      在这种情况下编译器应该怎么做?

      在某些情况下(例如在您的示例中),可以检测到 restrict 违规并被某些编译器检测到。例如,带有-Wrestrict 的 GCC 会产生警告:

      警告:将参数 1 传递给具有参数 2 的限制限定参数别名

      -Wrestrict 上的 GCC documentation 读取:

      restrict-qualified 参数(或者,在 C++ 中,__restrict-qualified 参数)引用的对象被另一个参数别名时,或者当此类对象之间的副本重叠时发出警告。

      您可以使用 -Werror=restrict 选项将此警告变为错误。

      【讨论】:

        猜你喜欢
        • 2011-04-12
        • 1970-01-01
        • 2014-07-27
        • 1970-01-01
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 2013-12-14
        • 2020-03-29
        相关资源
        最近更新 更多