代码之家  ›  专栏  ›  技术社区  ›  memorableusername

宏扩展中openmp pragma的替换不正确

  •  2
  • memorableusername  · 技术社区  · 7 年前

    当openmp pragma用作宏参数的一部分时,它会被错误地替换。 在本代码中:

    #define make_body( ... ) { __VA_ARGS__ }
    extern foo( int );
    int main(){
      make_body(
        #pragma omp parallel for
        for( int i = 0; i < 10; i += 1 ){
          foo( i );
        }
      )
    }
    

    我希望它可以扩展到:

    extern foo( int )
    int main(){
      {
        #pragma omp parallel for
        for( int i = 0; i < 10; i += 1 ){
          foo( i );
        }
      }
    }
    

    但是,(根据GCC-E),它扩大到:

    extern foo( int );
    int main(){
    #pragma omp parallel for
      { 
        for( int i = 0; i < 10; i += 1 ){ 
          foo( i ); 
        } 
      }
    }
    

    这是正确的行为吗? 如何获得预期的行为,最好不更改宏的参数? 所有的语用都会发生这种情况吗? 这是变量宏的作用吗? 其他编译器执行相同的替换吗?

    使用GCC(Ubuntu 5.4.0-6Ubuntu1~16.04.10)5.4.0 20160609

    2 回复  |  直到 7 年前
        1
  •  1
  •   John Bollinger    7 年前

    这是正确的行为吗?

    最准确的说法是 不错误 行为。标准对宏参数有这样的说明:

    如果在参数列表中有一系列的预处理令牌,否则它们将充当预处理指令,那么该行为是未定义的。

    您已经实践了这个案例,因此获得了未定义的行为。

    所有的语用都会发生这种情况吗?这是变量宏的作用吗?其他编译器执行相同的替换吗?

    该行为是未定义的,因此在一致性实现之间,甚至在同一个实现中,它可能因任何原因或无原因而有所不同。我想GCC在这方面是相对一致的,但你决不应该依赖它。它与涉及变量的宏无关。

    如何获得预期的行为,最好不更改宏的参数?

    gcc 5支持的c11针对发出pragma的宏的特定情况提供了解决方案: the _Pragma operator . 它更常用于文字宏替换文本中,这样您就可以有一个表示pragma的宏,但它也应该在宏参数中工作。但是,您必须稍微更改宏参数:

      make_body(
        _Pragma("omp parallel for")
        for( int i = 0; i < 10; i += 1 ){
          foo( i );
        }
      )
    
        2
  •  1
  •   zwol    7 年前

    不允许将任何预处理指令放入类似函数的宏的参数中。(C11) 6.10.3p11 ,最后一句。)

    在这种情况下,你 应该 能够写作 _Pragma("omp parallel for") 得到你想要的效果。实验表明,这对Clang和GCC(分别是7版和8版)都是正确的,但是 只有 您指定 -fopenmp 在命令行上。是的,即使使用 -E .