Take the following example:
#define FOO(x) bar x ## baz
FOO( )
What is the expected output of the above code, according to the ANSI C and C99 standards, after the preprocessing phase?
I ran the above through gcc -E
and clang -E
, and both produced output equivalent to the following:
bar baz
Also, if the above preprocessed output is considered to conform to the standards, then what about this?
#define FOO(x) x ## baz
FOO( )
With the above modification GCC and clang still produce output equivalent to the following, without emitting any warning or error (even with the -Wall -Werror
flags):
baz
The reason I am suspicious that the above output is not conformant to the standards is that the ANSI C 9899:1990 standard states:
6.8.3.3 The ## operator
A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form of macro definition.
If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence.
Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples, but x
does expand to... a single space? nothing? ...so the ## operator (at least, as I understand it) is concatenating a space pp-token (or nothing) to baz
.
Furthermore, the standard states:
For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.
So, considering the first example I gave above, why shouldn't the correct output be, say, this?
barbaz
As a sidenote, I did manage to get GCC to emit an error for the first example I gave above when preprocessing the code as follows:
gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -
The output (with error) is:
foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
bar baz
cc1: all warnings being treated as errors
The error, however, is not related to the behavior of the ## operator, which is what this question was all about. It's still interesting nonetheless.
Also interesting to note is that no error is emitted by clang when preprocessing the file, using the same flags.
Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,
The word "technically" here is redundant. The replacement list of both of your macros has x
before the ##
, so that rule doesn't apply.
but x does expand to... a single space? nothing?
6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.
So your whitespace in your argument to FOO
is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:
6.10.3.3 p2:
however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.
The next paragraph, 3, applies to the result here:
concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.
So, placemarker pasted onto baz
produces baz
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With