Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two adjacent ## operators

Can someone explain me why having 2 concatenation operators does not produce any error by a preprocessor?:

#define Z(x) x ## ## 3
Z(3)

results in:

33

Standards say that:

...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 I would expect that preprocesor first tries to concat x with second ## which seems strange. This does not produce any valid token so I would expect at least a warning. Neither gcc, nor VC produce any warning.

I would appreciate some explanation of how this works and why. Standard mentions placemaker temporary tokens which would explain why this works but there would have to be one such token between both 'double-sharps'. The problem is that placemaker tokens are generated when parameter contains no tokens and there is no parameter between both concat operators.

like image 475
Artur Avatar asked Jul 15 '15 14:07

Artur


1 Answers

(The C and C++ standards have essentially identical wording in §6.10.3.3 and §16.3.3 respectively. In case there are minor differences, I took the quotes from C11.)

The order in which ## operators are processed is explicitly unspecified: ("The order of evaluation of ## operators is unspecified.", last sentence of paragraph 3; also see paragraph 2 of the preceding section). So you can't say that the "preprocesor first tries to concat x with second ##"; it might first try to concat the first ## with the 3. That wouldn't produce a valid token, either, so it's a bit of a quibble. But it's important to remember.

The question is whether the statement that the order of evaluation being unspecified permits the evaluation to be interleaved. In other words, could a preprocessor satisfy the standard by first deleting the second ##, then deleting the first one, and finally producing a single concatenation? Certainly, in the execution model, it is clear that unsequenced operations are allowed to interleave. (See note 13 in §5.1.2.3. In C++, the words are "can overlap"; §1.9/13)

That might be a bit of a stretch, but it's also worth noting that after concatenation:

If the result is not a valid preprocessing token, the behavior is undefined.

This is not marked as a constraint, so an error message is not required. And since undefined behaviour relieves the compiler from any obligation to the standard, I suppose gcc is totally within its rights to produce the observed behaviour.

In short, the macro replacement string provided in the original question either involves unspecified or undefined behaviour, but not a constraint violation. Consequently, the compiler is under no obligation to produce a diagnostic.

Not producing a diagnostic in this case could be considered a quality-of-implementation issue. On the other hand, I don't know of any compiler which produces a warning for macros with ambiguous ## order of evaluation. Aside from the constraint that a macro expansion list cannot start or end with a ## token, which must be diagnosed by the compiler, it is wholly the responsibility of the programmer to ensure that concatenation expressions are well-defined.

like image 156
rici Avatar answered Sep 19 '22 12:09

rici