C 宏扩展中OpenMP Pragma的替换不正确

C 宏扩展中OpenMP Pragma的替换不正确,c,gcc,macros,openmp,variadic-macros,C,Gcc,Macros,Openmp,Variadic Macros,当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 ); } ) } #定义make_body(…){{uuuu VA

当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 );
    }
  )
}
#定义make_body(…){{uuuu VA_ARGS}
外务主任(内务);
int main(){
做你的身体(
#pragma-omp并行
对于(int i=0;i<10;i+=1){
富(i),;
}
)
}
我希望它将扩大到:

extern foo( int )
int main(){
  {
    #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 ); 
    } 
  }
}
extern foo(int)
int main(){
{
#pragma-omp并行
对于(int i=0;i<10;i+=1){
富(i),;
}
}
}
然而,(根据gcc-E),它扩展到:

extern foo( int )
int main(){
  {
    #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 ); 
    } 
  }
}
extern foo(int);
int main(){
#pragma-omp并行
{ 
对于(inti=0;i<10;i+=1){
富(i),;
} 
}
}
这是正确的行为吗? 如何获得预期的行为,最好是不更改宏的参数? 所有的布拉格语都是这样吗? 这是可变宏的影响吗? 其他编译器是否执行相同的替换


使用gcc(ubuntu5.4.0-6ubuntu1~16.04.10)5.4.0 20160609,不允许将任何预处理指令放入函数类宏的参数中。(C11,最后一句。)

在这种情况下,您应该能够编写
\u Pragma(“omp parallel for”)
并获得想要的效果。实验表明,这在clang和gcc(分别为版本7和版本8)中都能正常工作,但前提是在命令行上指定
-fopenmp
。是,即使使用
-E

这是正确的行为吗

最准确的说法是,这不是不正确的行为。该标准对宏参数有如下规定:

如果在参数列表中有一系列预处理标记,否则这些标记将充当预处理指令,则该行为是未定义的

您已经使用了该案例,并因此获得了未定义的行为

所有的布拉格语都是这样吗?这是可变宏的影响吗?其他编译器是否执行相同的替换

该行为是未定义的,因此它可能在一致性实现中有所不同,甚至在同一个实现中也可能因任何原因而有所不同。我想GCC在这方面是相对一致的,但无论如何你都不应该依赖它。它并不特别与可变的宏相关

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

GCC 5支持的C11针对发出杂注的宏的特定情况提供了一个解决方案:。它更常用于文字宏替换文本中,因此可以有一个表示pragma的宏,但它也应该在宏参数中工作。但是,您必须稍微更改宏参数:

  make_body(
    _Pragma("omp parallel for")
    for( int i = 0; i < 10; i += 1 ){
      foo( i );
    }
  )
make_体(
_Pragma(“omp并行用于”)
对于(int i=0;i<10;i+=1){
富(i),;
}
)

替代解决方案这修复了我们在实际代码中看到的一个案例,在这里重新创建这个案例非常重要(但我们并不确切知道为什么会发生这种情况)。
-fopenmp
也是必需的

#define EMPTY()
#define DELAY(x) x EMPTY()
#define STRINGIZE(x) STRINGIZE_NO_PREPROCESS(x)
#define STRINGIZE_NO_PREPROCESS(x) #x

#define PRAGMA(x) _Pragma( STRINGIZE(x) )
#define DELAYED_PRAGMA_assist(x) PRAGMA(x)
#define DELAYED_PRAGMA DELAY(DELAYED_PRAGMA_assist)

#define PRAGMA_IN_MACRO_ARG(x) DELAYED_PRAGMA(x)
#define PRAGMA_IN_MACRO_BODY(x) PRAGMA(x)
PRAGMA\u在\u MACRO\u ARG中
可用于在将代码作为参数传递给另一个宏时正确放置PRAGMA 例如:

#define WRAP( body ) { body }

#define loop( i, N, body )\
if( N > 0 ) \
WRAP( \
  PRAGMA_IN_MACRO_ARG(omp parallel for private(i)) \
  for( i = 0; i < N; ++i ){ \
      body \
  } \
)

loop( i, 10, printf("%d\n", i); )
#define loop( i, N, body )\
if( N > 0 ) \
{\
  PRAGMA_IN_MACRO_BODY(omp parallel for private(i)) \
  for( i = 0; i < N; ++i ){ \
      body \
  } \
}

loop( i, 10, printf("%d\n", i); )

我很好奇:真正的目标用例是什么?问题中给出的示例不可能是它,因为像普通人一样输入literal
{}
会更简单,也不那么麻烦。真正的用例是一个代码计时库,它在代码部分周围插入计时器停止、启动和时间流逝报告代码。到目前为止,它一直工作得很好,但不幸的是,这个OpenMP示例破坏了一切。为了解决这个问题,我将为这些单独的组件添加一些宏,这样代码部分就不是一个宏参数。Boo To undefined behavior!感谢您的详细解释。_Pragma是C99的一项功能,已经有近20年的历史了!我要强调的是最后一部分,因为它真的让我很难受。对于openmp,您必须使用
-fopenmp
才能工作: