2

I consistently run into compiler errors where I forget to put the opening brace for a #pragma omp critical section on the line following the statement, instead of on the same line:

  #pragma omp parallel 
  {

  static int i = 0;

  // this code fails to compile
  #pragma omp critical {
    i++;
  }

  // this code compiles fine
  #pragma omp critical 
  {
    i++;
  }

  }

My question is, why can't the compiler parse the braces on the same line? It can do this for any C++ syntax. Why should white space matter for the OpenMP #pragma statements, when it does not in C++?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
v2v1
  • 640
  • 8
  • 18
  • 4
    Generally, any line beginning with `#` is a compiler directive and doesn't contribute to the final source code, so a `{` appearing on the same line wouldn't be matched to the closing `}` of the scope you've declared – alter_igel Mar 15 '18 at 21:04
  • 1
    For years I've been told real C programmers put brackets on new lines – tim18 Mar 15 '18 at 22:48
  • 1
    Why is the the banana curved? Because god made it so. Why can you not put `{` in the same line? Because the gods of C/preprocessor decided so. – Walter Mar 16 '18 at 00:25
  • 2
    Do you expect `#include {` to work too? – Jonathan Wakely Mar 16 '18 at 00:26
  • 1
    Another reason, not mentioned here, is that even if it was possible, then your program wouldn't be compilable without OpenMP support, since then, the whole `#pragma omp ...` line would be ignored. This is nice about OpenMP that you can write a single source code and compile it even without OpenMP support to make a sequential version of your program. – Daniel Langr Mar 16 '18 at 09:16

3 Answers3

8

According to cppreference:

The preprocessing directives control the behavior of the preprocessor. Each directive occupies one line and has the following format:

  1. # character

  2. preprocessing instruction (one of define, undef, include, if, ifdef, ifndef, else, elif, endif, line, error, pragma)

  3. arguments (depends on the instruction)

  4. line break.

The null directive (# followed by a line break) is allowed and has no effect.

So the pre-processor, not the compiler, reads the entire line as a directive. Unlike the compiler, which does not care about line breaks.

Source: http://en.cppreference.com/w/cpp/preprocessor

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Gabriel
  • 829
  • 5
  • 12
  • 1
    If we start preprocessor as separate command `/usr/bin/cpp` or `gcc -E`, how will it process (pre-process) the OpenMP pragma? Pragmas have syntax of preprocessore directives, but they are actually processed (used) by later stages of parsing process. – osgx Mar 16 '18 at 00:48
  • @osgx `#pragma omp` directives pass through `cpp` or `gcc/g++ -E` virtually unchanged (the `#` is shifted to the first column, but that's all), they're left for those later stages to process. Keep in mind that `#pragma` itself _is_ a preprocessor directive, (e.g. `#pragma once` is handled by the preprocessor), but it's also allowed to pass through any unknown pragmas. That's why all of the OpenMP directives are `#pragma omp ...`. – FeRD Sep 27 '20 at 20:25
4

Because it does.

To say that whitespace "never matters" in any C++ construct is foolhardy. For example, the following pieces of code are not the same, and I don't believe that anyone would expect them to be:

1.

int x = 42;

2.

intx=42;

It is more true to say that newlines and space characters are generally treated in the same way, but that's still not quite right. Like:

3.

 void foo() // a comment
 {

4.

 void foo() // a comment {

Of course, in this case, the reason the snippets aren't the same is because // takes effect until the end of the line.

But so does #.

Both constructs are resolved by the preprocessor, not by the compiler, and the preprocessor works in lines. It is not until later in the build process that more complex parsing takes place. This is logical, consistent, predictable, and practical. All syntax highlighters expect it to work that way.

Could the preprocessor be modified to treat a { at the end of a preprocessor directive as if it were written on the next line? Sure, probably. But it won't be.

Thinking purely about this actual example, the range of acceptable parameters to a #pragma is implementation defined (in fact this is the whole point of the #pragma directive), so it is literally not possible for the C++ standard to define a more complex set of semantics for it than "use the whole line, whatever's provided". And, without the C++ standard guiding it, such logic would potentially result in the same source code meaning completely different things on completely different compilers. No thanks!

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

My question is, why can't the compiler parse the braces on the same line? It can do this for any C++ syntax. Why should white space matter for the OpenMP #pragma statements, when it does not in C++?

There are two standards which defines what compiler can: C/C++ language standard and OpenMP specification. C/C++ specification of OpenMP says (chapter 2, 10-11; 2.1 7):

In C/C++, OpenMP directives are specified by using the #pragma mechanism provided by the C and C++ standards.

2.1 Directive Format The syntax of an OpenMP directive is as follows:

 #pragma omp directive-name [clause[ [,] clause] ... ] new-line

So, new line is required by OpenMP (and by syntax of #pragma in C and C++ standards - while they look like preprocessor directive, they are actually compiler directives).

But if you want to use OpenMP pragmas in places where newlines are prohibited (inside macro directive) or you want to place { on the same line, sometimes there is alternative: _Pragma (from C99 standard and from C++11 standard) or non-standard MS-specific __pragma: Difference between #pragma and _Pragma() in C and https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

_Pragma("omp parallel for")
_Pragma("omp critical")

This variant may work in some C++ compilers and may not work in another; it also depends on language options of the compilation process.

osgx
  • 90,338
  • 53
  • 357
  • 513