Search code examples
c++cconcatenationtokenc-preprocessor

Why does the ## aka token-pasting operator not work for comments in C and C++?


Why does the following error occur?

#include <iostream>

#define concatenate(t1, t2) t1 ## t2 // Concatenate token1 and token2

int main()
{
    int myVar = 22;
    std::cout << concatenate(my, Var); // Compiles fine and outputs the value of myVar

    concatenate(/, /) So I thought that this would be a comment but this is a compile-time error
    // error: pasting "/" and "/" does not give a valid preprocessing token

    return 0;
}

I thought that concatenate(/, /) would tell the preprocessor to replace it with a // and then as it parses further, that entire line would be interpreted as a comment.

What is actually happening in this case?


Solution

  • This answer is for C, it's similar in C++.

    The example is literally the same as in C11 standard 6.4.9p3:

          #define glue(x,y) x##y
          glue(/,/) k();                     // syntax error, not comment
    

    The error you are seeing:

    error: pasting "/" and "/" does not give a valid preprocessing token

    comes from that the result of ## needs to be preprocessing tokens. In short, a preprocessing token are identifiers, preprocessing numbers, string literals, punctuators, and other. (See also gcc docs on tokenization). The resulting // string is not a preprocessing token, so the result of ## here would not be a preprocessing token. The C standard 6.10.3.3p3 states that if a result of ## "is not a valid preprocessing token, the behavior is undefined". The compiler you are using chooses to issue an error in such case. It will not work the same way as the following do not work:

    concatenate(:, b) // error, `:b` is not a preprocessing token
    concatenate(%, b) // error, `%b` is not a preprocessing token
    // etc.
    

    Maybe for example from the other side, for example %= is a valid token, a punctuator. The following are ok:

    concatenate(%, =)
    concatenate(/, =)
    concatenate(a /, = b)
    concatenate(<, :)
    

    Anyway, even if // would be a valid preprocessing, comments are substituted for a single space in translation phase 3, while the preprocessor is executed in translation phase 4 after comments are removed, see C11 translation phases. So, even if it would result in // token, it would be invalid, as it doesn't mean anything in C (except comments).