3

Please consider the following minimal example:

#include <stdio.h>

// Compile with:
// gcc -g -o myprogram main.c

//#define SPECIAL

typedef struct {
  int id;
  char name[50];
  float value;
} MyStruct;

MyStruct example = {
  #ifdef SPECIAL
  .id = 43,
  #else
  #pragma message("Hello from structure")
  .id = 42,
  #endif
  .name = "Example Name",
  .value = 3.14f,
};

int main() {
  printf("ID: %d\n", example.id);

  return 0;
}

When I try to build this, I get:

$  gcc -g -o myprogram main.c && ./myprogram
main.c:18:11: error: expected expression before ‘#pragma’
   18 |   #pragma message("Hello from structure")
      |           ^~~~~~~

Compiler I use:

$  gcc --version | head -1
gcc (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0

I always thought, the preprocessor is independent of C code, so I can put preprocessor statements wherever I want? So is the problem here that I have the #pragma message in between initializing fields of a structure? But then - there is no problem using #if etc in between fields of a structure, as the above example shows if you comment the #pragma message line ?!

So - is there any way to get this #pragma message to work at the position it is in?

1
  • You're using GCC 11.4.0, I see. With GCC 15.2.0 on macOS Tahoe 26.0.1, I get the warning message and (because I have -std=c18 -Werror=strict-prototypes set) an error about the definition (declaration) of main. WIth -std=c23, that goes away. Commented Oct 23 at 15:06

2 Answers 2

8

That is actually a long running half-bug half-design-inconsistency in the gcc itself.

It boils down to a "#pragma is a statement". Pragmas can be used anywhere a statement can, but not be part of another statement. Even if other preprocessor's words like #define and #ifdef can.

Said that, the easiest way to solve your problem is to move the #pragma message out of struct definition and replace it with a special define:

#include <stdio.h>

// Compile with:
// gcc -g -o myprogram main.c

//#define SPECIAL

typedef struct {
  int id;
  char name[50];
  float value;
} MyStruct;

MyStruct example = {
  #ifdef SPECIAL
  .id = 43,
  #else
  #define HIT_STRUCT_WITH_42
  .id = 42,
  #endif
  .name = "Example Name",
  .value = 3.14f,
};

#ifdef HIT_STRUCT_WITH_42
  #pragma message("Hello from structure")
#endif

int main() {
  printf("ID: %d\n", example.id);

  return 0;
}
Sign up to request clarification or add additional context in comments.

4 Comments

To be clear, by "#pragma is a statement", do you mean that GCC treats #pragmas as if they were statements? Because they definitely are not statements as far as the C language spec is concerned. All the same, GCC is free to behave that way, because #pragma directives where STDC does not immediately follow the directive name have implementation-defined behavior. That's pretty much their whole point.
I note also that for the STDC pragmas defined by the standard, all have this or a substantially equivalent statement in their descriptions: "The pragma can occur either outside external declarations or preceding all explicit declarations and statements inside a compound statement." That seems to be pretty close to what GCC requires of other pragmas, so there is consistency in that sense. If you want to consider it an inconsistency that other preprocessing directives can be used more freely then that falls on the language spec. I don't see a reason to characterize it as a bug in GCC.
Another option would be to use _Pragma("message(\"Hello from structure\")"). That may still be subject to some gotchas, though.
I think this is one of the reasons why _Pragma was added to the C standard.
2

I always thought, the preprocessor is independent of C code, so I can put preprocessor statements wherever I want?

This is true of most preprocessor directives, given a not-too-strict interpretation of "can" and "wherever", but it is not true of pragmas in general.

We have to classify pragmas into two categories:

  1. Those in which the first preprocessor token after the initial pragma is STDC.

    The spec defines several specific variations on pragmas of this form, and demands that no other pragmas of this form appear. All of these have the same limitation on where they can appear. Taking #pragma STDC FP_CONTRACT ON as an example, C24 7.12.3/2 says:

    Each pragma can occur either outside external declarations or preceding all explicit declarations and statements inside a compound statement

    That should be read as a restriction, else it would be meaningless. It is thus a fairly strong constraint on where such pragmas can appear.

    It is also, therefore, somewhat problematic, in that the C translation model (C24 5.2.1) has the effects of pragmas being applied during translation phase 4 (and the pragmas then being removed, along with all other preprocessing directives), but the boundaries of declarations and statements are not determined until phase 7. The language spec leaves it to implementations to sort that out.

  2. All other pragmas.

    One of these ...

    causes the implementation to behave in an implementation-defined manner.

    (C24 6.10.8/1)

    That leaves behavior wide open, as long as the implementation defines it, and explicitly (not quoted) allows for the compiler to reject the program. Since C requires compilers to be restrictive about where group (1) pragmas appear, it should not be too surprising if they are equally restrictive about where others can appear. "Implementation defined" gives compilers license to do so.

So is the problem here that I have the #pragma message in between initializing fields of a structure?

The diagnostic seems to indicate so, and I anticipate that lifting the #pragma directive out of the definition of example would satisfy the compiler. You'll have to try and see, or rely on someone else who already has done so, or on someone familiar with GCC's implementation, because that pragma is documented in the GNU C Preprocessor Manual, and neither that manual nor GCC's speaks at all to where pragmas can appear.

there is no problem using #if etc in between fields of a structure, as the above example shows if you comment the #pragma message line ?!

Correct. Pragmas are weird, and best avoided. All other preprocessing directives have well defined effects that are limited to the preprocessing token stream and the preprocessing of it, and no implementation I know of limits where in the token stream they can appear relative to the C-language syntactic constructs into which the tokens will later be grouped.

So - is there any way to get this #pragma message to work at the position it is in?

That's a question about GCC, not about the C language itself, but I would think not.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.