2

Consider this code:

/* 
 * stdio.h
 * 
 * note: it is an example of a particular implementation of stdio.h
 * containing _x; it is not "my code added to stdio.h"
 */
void _x(void);

/* t627.c */
#define _x 0
#include <stdio.h>

Invocation:

$ gcc t627.c

t627.c:1:12: error: expected identifier or ‘(’ before numeric constant
    1 | #define _x 0
      |            ^
stdio.h:1:6: note: in expansion of macro ‘_x’
    1 | void _x(void);

At translation phase 4 the identifier _x is non-reserved. At translation phase 7 the identifier _x is reserved (for use as identifier with file scope in both the ordinary and tag name spaces). Since translation phase 4 precedes translation phase 7, then at translation phase 7 the identifier _x (currently defined as a macro name) is already replaced by its replacement list 0, invalidating the program.

Does it mean that in cases when the user-defined macro (that begins with an underscore, followed by a lowercase letter) can collide/overlap with the file scope identifier with the same name, such file scope identifier cannot be reserved?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
pmor
  • 5,392
  • 4
  • 17
  • 36
  • @JonGreen gives an excellent answer below. But I just wanted to point out that it is a VERY bad idea to modify any of the C standard library headers (such as `stdio.h`). Instead, put your `#define`s and such in a local header file, perhaps called `t627.h`. – SGeorgiades Jul 24 '22 at 22:31
  • Note that you should not, in general, create function, variable, tag or macro names that start with an underscore. Part of [C11 §7.1.3 Reserved identifiers](https://port70.net/~nsz/c/c11/n1570.html#7.1.3) says: — _All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use._ — _All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces._ See also [What does double underscore (`__const`) mean in C?](https://stackoverflow.com/q/1449181) – Jonathan Leffler Jul 25 '22 at 00:59
  • You can avoid such problems by avoiding names starting with underscores. Or you can live with the possibility of a conflict. IMO, it's easier to avoid the possibility of a conflict. The biggest problem comes when an implementation decides to use a name that you've been using for years — you now have an irresistible force meeting an immovable object. You can run into that problem with unreserved names too. Witness `getline()` in K&R "The C Programming Language" vs `getline()` in POSIX. – Jonathan Leffler Jul 25 '22 at 01:01

3 Answers3

2

#define macros are always a textual substitution.

Headers, of course, are not compiled entities in their own right, so are only evaluated at the point they are #included.

Let's say you have a header containing a certain non-macro identifier*.

In a C module, you #define that same identifier to expand to something arbitrary and pathological, and then #include the header

Since the compiler encounters the #define before it encounters the #include, all mentions in the header of the colliding identifier will be substituted with the macro's expansion. The consequences can be (and often are) disastrous, or at the very least hard to debug.

It doesn't really matter whether or not the identifier starts with an underscore. If you wrote #define printf scanf, just for instance, that would cause chaos!


(* I stipulate "non-macro" just to avoid the complications of what would happen if the header redefined - or tried to - the macro you defined first.)

Jon Green
  • 345
  • 2
  • 5
1

You're not allowed to define macros with any of the reserved names. This is stated explicitly in section 7.1.3p2 of the C standard:

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.

(Boldface: my emphasis.)

To put it another way, every identifier that is reserved in some phase-7 context is also reserved for use as a macro name.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • The question is not about macro with reserved identifier. The question is about macro with non-reserved identifier. Per C all identifiers that begin with an underscore, followed by a lowercase letter AND used as macros are non-reserved. – pmor Jul 27 '22 at 21:37
  • I guess there's some ambiguity in the text I quoted, but I read the boldface part as meaning "if the program defines an identifier *that could be reserved in some context* as a macro name, the behavior is undefined". – zwol Jul 27 '22 at 22:12
  • I read "defines a reserved identifier as a macro name" exactly (i.e. w/o ambiguity). And at translation phase 4 the identifier `_x` (for example) is non-reserved. Hence, the boldface part is irrelevant because the program _doesn't_ "define a reserved identifier as a macro name". I think that key point here is that an _overlapping_ may occur (see my answer). Hence, you cannot use function named `_x` (for example) in libc header because the user may use `_x` as a macro name (which will overlap with the function named `_x`). – pmor Jul 28 '22 at 16:23
  • Have a look: https://sourceware.org/bugzilla/show_bug.cgi?id=29399. – pmor Jul 28 '22 at 16:34
  • I posted over there, but I don't agree with your interpretation; it would make the boldface clause redundant. The standard should be read as though every word is present on purpose. – zwol Jul 28 '22 at 19:41
  • In my view the boldface clause is not redundant. Example: `printf` is a reserved identifier as a macro name. Hence, `#define printf 0` leads to UB. While `_x` (for example) is non-reserved identifier as a macro name. Hence, `#define _x 0` does not lead to UB. – pmor Jul 29 '22 at 06:38
0

Found a relevant quote from P.J. Plauger (emphasis added):

Remember that the user can write macros that begin with an underscore, followed by a lowercase letter. These names overlap those reserved to the implementor for naming external functions and data objects.

So, the answer seems to be "yes".

pmor
  • 5,392
  • 4
  • 17
  • 36