11

In implementing my own C11 compiler, I'm trying to figure out how exactly to handle the _Pragma keyword/operator. C11 §6.10.9 describes _Pragma as being an operator, so it seems possible to redefine it with macros, i.e. #define _Pragma(x) SOME_OTHER_MACRO(x). Further, the statement #undef _Pragma should have no effect (assuming no prior #define of _Pragma). This is similar to how keywords can be #defined, such as the old VC++ hack #define for if (0) ; else for. However, because the _Pragma operator is evaluated during translation phase 3, the same phase as executing preprocessor directives, it's not clear whether this is an exception; the standard doesn't mention whether its undefined behavior to use _Pragma as a macro name.

I did some testing with GCC using the following code:

#define PRAGMA _Pragma
PRAGMA("message \"hi\"")

_Pragma ("message \"sup\"")

#undef PRAGMA

#undef _Pragma
//#define _Pragma(x)
_Pragma("message \"hello\"")

Compiling with gcc -std=c11 -pedantic -Wall -Wextra -c outputs:

tmp.c:2:1: note: #pragma message: hi
 PRAGMA("message \"hi\"")
 ^
tmp.c:4:1: note: #pragma message: sup
 _Pragma ("message \"sup\"")
 ^
tmp.c:8:8: warning: undefining "_Pragma" [enabled by default]
 #undef _Pragma
        ^
tmp.c:10:9: error: expected declaration specifiers or ‘...’ before string constant
 _Pragma("message \"hello\"")
         ^

If I add the line #undef _Alignof, GCC doesn't complain about it.

This suggests that GCC implements _Pragma through a macro (via the warning message), and that undefining it results in a compile error. If I uncomment #define _Pragma(x), the error goes away (as the string literal disappears).

So, my questions are:

  1. Are implementations allowed to define _Pragma as just a macro, and not implement it as an operator?
  2. If not, is GCC wrong in doing so?
  3. if _Pragma is supposed to be an operator, is it undefined behavior to define _Pragma as a macro?
  4. Is there any ordering between _Pragma evaluation and other preprocessor directives? Or do they have the same "precedence" (i.e. they're evaluated in-order)?

Again, looking through the C11 standard does not mention anything about _Pragma other than it's an operator that can be used for #pragma directives.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • 2
    Anticipate some substantial level of opinion will play a roll in the answers you get to this question, ( like the `void main(void)` discussions ) however, your research is evident, and your questions are well presented. Should result in interesting responses. (+1) – ryyker Jul 23 '14 at 16:39
  • I'm not sure, if I understand the standard correctly here, but I think, C11 7.1.3 p3 applies: “If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined.” where the mentioned “first group” are identifiers beginning with an underscore followed by another underscore or an uppercase letter. – mafso Jul 23 '14 at 18:27
  • @mafso that seems to only apply if there's a macro definition in the first place, so code like `#ifndef _Pragma #undef _Pragma#endif` would not invoke UB – Drew McGowen Jul 23 '14 at 18:57
  • @DrewMcGowen - If the C11 standard defines _Pragma as _A unary operator expression of the form:_ ***_Pragma (*** string-literal ***)***..., And an implementation chooses to implement it in a different way, would that other implementation be considered C? (reference 6.10.9 Pragma operator, in C11 standard, Committee Draft — April 12, 2011) – ryyker Jul 23 '14 at 20:23
  • "similar to how keywords can be #defined, such as the old VC++ hack #define for if (0) ; else for" — …wow. I never heard of this before — https://stackoverflow.com/questions/984878/what-is-the-possible-use-for-define-for-if-false-else-for – Rusty Shackleford Feb 20 '18 at 21:45

1 Answers1

7

There is no need for a special rule that would forbid _Pragma to be a macro name. Having a leading underscore and capital letter, it is among the reserved identifiers that you are not supposed to use, anyhow. Using reserved identifiers leads to undefined behavior of your program, a compiler may do anything.

An implementation may implement it as a macro, but that should be transparent to you, as long as you use it correctly, that is as long as you don't mess around with it. The only important thing that an implementation must guarantee is that the "destringization" and "tokeninzation" of the argument to the _Pragma is done as if in phase 3 (which is difficult if it is "only" a macro) and that the resulting #pragma directive is processed in phase 4.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • It's almost unclear what the standard means by "reserved for any use" - surely, a statement such as `int ln = __LINE__;` could be considered a use of the identifier `__LINE__` (unless "reserved for any use" does not include mandatory identifiers). – Drew McGowen Jul 23 '14 at 20:25
  • @DrewMcGowen: "reserved for any use" means that the user cannot declare or define identifiers of that form for any use (since it's reserved). Contrast that with identifier forms that are reserved only for identifiers with file scope or only if a specific header is included. – Michael Burr Jul 23 '14 at 21:02
  • 2
    @DrewMcGowen, this has a very precise meaning which is provided in 7.1.3. Paragraph 2 says what you are not supposed to do with it: *If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.* – Jens Gustedt Jul 23 '14 at 21:06
  • _Having a leading underscore and capital letter, it is among the reserved identifiers that you are not supposed to use,..._ +1 – ryyker Jul 23 '14 at 21:17
  • Is `_Pragma` a "full citizen" as a C operator? I mean, would `int *c = _Pragma(ObscureIntAllocator);` be legal C code? – cesss Nov 28 '20 at 11:06