C Preprocessor Token-Pasting Operator

C/C++ preprocessing

Posted by Bruce Lee on 2024-05-08

Token Pasting in the C Preprocessor

The token-pasting operator ## is handled by the C preprocessor. It is not an operator in ordinary C expressions. In practice, that means it can be used inside a macro replacement list, but not directly inside normal C code.

Here is a minimal example:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

#define concat(x, y) x ## y

int main(int argc, char** argv)
{
int concat(x, y) = 32;
printf("%d\n", concat(x, y));
return 0;
}

After compiling and running it:

1
2
gcc demo.c
./a.out

the program prints:

1
32

The macro call concat(x, y) is expanded by the preprocessor. The two tokens x and y are pasted into a single token, xy.

Inspecting the Preprocessed Source

For this line:

1
int concat(x, y) = 32;

the identifier is constructed during preprocessing. You can inspect the preprocessed output with:

1
gcc -E demo.c -o demo.i

Near the end of demo.i, the code becomes:

1
2
3
4
5
6
7
# 4 "demo.c"
int main(int argc, char** argv)
{
int xy = 32;
printf("%d\n", xy);
return 0;
}

This is the actual C source that the compiler receives after preprocessing. There is no remaining call to the concat macro.

What Happens Outside a Macro

If ## is written directly in C code instead of inside a macro, the preprocessor has no macro replacement list to apply it to.

For example:

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main(int argc, char** argv)
{
int x ## y;
xy = 32;
printf("x ## y equal %d\n", xy);
return 0;
}

or:

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main(int argc, char** argv)
{
int xy;
x ## y = 32;
printf("xy equal %d\n", xy);
return 0;
}

Compiling this with:

1
gcc demo1.c

produces an error such as:

1
error: stray '##' in program

The first error is usually the most useful one. Later diagnostics are often just consequences of the first syntax error.

If you still run the preprocessing step:

1
gcc -E demo1.c -o demo1.i

the tail of the output still contains the ## tokens:

1
2
3
4
5
6
7
8
# 2 "demo1.c"
int main(int argc, char** argv)
{
int x ## y;
xy = 32;
printf("x ## y equal %d\n", xy);
return 0;
}

That explains the diagnostic. Since ## was not used as part of macro replacement, the preprocessor left it in place. The compiler then sees tokens that are not valid C syntax and reports an error.

Practical Rule

Preprocessor operators such as ## belong to preprocessing constructs like macro definitions. They are resolved before the compiler proper starts parsing C syntax. Once normal C parsing begins, ## is no longer meaningful.


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !