我一直遇到编译器错误,我忘记在语句后面的行上放置#pragma omp critical
部分的左括号,而不是在同一行:
#pragma omp parallel
{
static int i = 0;
// this code fails to compile
#pragma omp critical {
i++;
}
// this code compiles fine
#pragma omp critical
{
i++;
}
}
我的问题是,编译器为什么不能在同一行上解析大括号?它可以为任何C ++语法执行此操作。为什么白色空间对OpenMP #pragma
语句很重要,当它不在C ++中时?
答案 0 :(得分:5)
根据cppreference:
预处理指令控制预处理器的行为。 每个指令占用一行,格式如下:
#
字符预处理说明(
define
,undef
,include
,if
,ifdef
,ifndef
,{{1 }},else
,elif
,endif
,line
,error
)参数(取决于指令)
- 醇>
换行。
允许使用null指令(#后跟换行符),但不起作用。
所以预处理器,而不是编译器,将整行读作指令。不像编译器,它不关心换行符。
答案 1 :(得分:4)
因为它确实如此。
说空白"永远不重要"在任何C ++构造中都是蛮干的。例如,以下几段代码不一样,我不相信任何人都会期望它们是:
int x = 42;
intx=42;
更确切地说,换行符和空格字符通常以相同的方式处理,但这仍然不太正确。像:
void foo() // a comment
{
void foo() // a comment {
当然,在这种情况下,片段不相同的原因是因为//
生效直到行尾。
但 #
也是如此。
两个构造都由预处理器解析,而不是由编译器解析,预处理器在行中工作。直到构建过程的后期才会发生更复杂的解析。这是合乎逻辑的,一致的,可预测的和实用的。所有语法高亮显示器都希望它以这种方式工作。
是否可以修改预处理器以在预处理器指令的末尾处理{
,就好像它是在下一行写的一样?当然可能。但它不会成为。
纯粹考虑这个实际的例子,#pragma
的可接受参数范围是实现定义的(实际上这是#pragma
指令的全部要点),所以它几乎不可能C ++标准为它定义一组更复杂的语义而不是"使用整行,无论提供什么"。并且,如果没有C ++标准指导它,这样的逻辑可能会导致相同的源代码意味着在完全不同的编译器上完全不同的东西。不,谢谢!
答案 2 :(得分:1)
我的问题是,编译器为什么不能在同一行上解析大括号?它可以为任何C ++语法执行此操作。为什么白色空间对OpenMP #pragma语句很重要,当它不在C ++中时?
有两个标准可以定义编译器可以使用的内容:C / C ++语言标准和OpenMP specification。 C / C ++ specification of OpenMP says (chapter 2, 10-11; 2.1 7):
在C / C ++中,OpenMP指令是使用C和C ++标准提供的#pragma机制指定的。
2.1指令格式 OpenMP指令的语法如下:
#pragma omp directive-name [clause[ [,] clause] ... ] new-line
因此,OpenMP需要新行(并且在C和C ++标准中使用#pragma
的语法 - 虽然它们看起来像预处理器指令,但它们实际上是编译器指令)。
但是如果你想在禁止换行的地方(在宏指令内)使用OpenMP pragma,或者你想在同一行放置{
,有时可以选择:_Pragma
(来自C99)标准和来自C++11 standard)或非标准MS特定__pragma
:Difference between #pragma and _Pragma() in C和https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html
_Pragma("omp parallel for")
_Pragma("omp critical")
此变体可能在某些C ++编译器中有效,但在另一个C ++编译器中可能无效;它还取决于编译过程的语言选项。