Use of # in a macro [duplicate]

2020-06-10 06:29发布

问题:

Please explain the code

#include <stdio.h>
#define A(a,b) a##b
#define B(a) #a
#define C(a) B(a)

main()
{
 printf("%s\n",C(A(1,2)));
 printf("%s\n",B(A(1,2)));
}

Output

12

A(1,2)

I don't understand, how the first printf evaluates to 12? Isn't it similar to the second, as C macro is simply a wrapper to B macro?

回答1:

The confusion here comes from a simple rule.

When evaluating a macro the pre-processor first resolves the macros in the arguments passed to the macro. However, as a special case, if an argument is right of # or adjacent to ##, it doesn't resolve macros within such arguments. Such are the rules.

Your first case

C(A(1,2))

The pre-processor first applies the C(a) macro, which is defined as B(a). There's no # or ## adjacent to the argument in the definition (none of them in B(a) at all), thus the pre-processor must resolve macros in the argument:

A(1,2)

The definition of A(a,b) is a##b which evaluates into 12.

After the macros in the arguments of the C(a) macro are evaluated, the C macro becomes:

C(12)

The pre-processor now resolves the C(a) macro, which according to its definition becomes

B(12)

Once this is done, the pre-processor evaluates macros inside the result once again and applies the B(a) macro, so the result becomes

"12"

Your second case

B(A(1,2))

Similar to the first case, the pre-processor first applies the B(a) macro. But this time, the definition of the macro is such that the argument is preceded by #. Therefore, the special rule applies and macros inside the argument are not evaluated. Therefore, the result immediately becomes:

"A(1,2)"

The preprocessor goes over the result again trying to find more macros to expand, but now everything is a part of the string, and macros don't get expanded within strings. So the final result is:

"A(1,2)"


回答2:

As mentioned in Wikipedia in C-preprocessor :

The ## operator (known as the "Token Pasting Operator") concatenates two tokens into one token.

The # operator (known as the "Stringification Operator") converts a token into a string, escaping any quotes or backslashes appropriately.

If you want to stringify the expansion of a macro argument, you have to use two levels of macros:

You cannot combine a macro argument with additional text and stringify it all together. You can however write a series of adjacent string constants and stringified arguments: the C compiler will then combine all the adjacent string constants into one long string.

#define xstr(s) str(s)
#define str(s) #s
#define foo 4

str (foo)  // outputs "foo"
xstr (foo) // outputs "4"

Also, from C-FAQ Question 11.17 :

It turns out that the definition of # says that it's supposed to stringize a macro argument immediately, without further expanding it (if the argument happens to be the name of another macro).

So, similarly, going along these lines :

you're doing C(A(1,2)), 
which would roll to C(12), // since no #, so inner argument is expanded
and then to B(12)
// [since you've done two levels of macros in the code:
// 1. from C() to B(), and then, 2. B() to #a]
= 12 . 

Whereas, in the first case, only 1 level of stringification is plainly done as per definition of B(a)(since it gets stringified immediately because of #)

macro-replacement of B(A(1,2)) 
= stringification of A(1,2) 
= A(1,2).


回答3:

C preprocessor has two operators # and ##. The # operator turns the argument of a function like macro to a quoted string where ## operator concatenates two identifiers.

#define A(a,b) a##b will concatenate a with b returning ab as string.
so A(1,2) will return 12
#define B(a) #a  will return a as string
#define C(a) B(a) will call previous one and return a as string.
so C(A(1,2)) = C(12) = B(12) = 12 (as string)
B(A(1,2)) = A(1,2) because A(1,2) is taken as an argument and returned as string A(1,2) 


回答4:

There are two operators used in the function-like macros:

  • ## causes a macro to concatenate two parameters.
  • # causes the input to be effectively turned into a string literal.

In A(a,b) ## causes a to be concatenated with b. In B(a), # effectively creates a string literal from the input. So the expansion runs as follows:

C(A(1,2)) -> C(12) -> B(12) -> "12"
B(A(1,2)) -> "A(1,2)"

Because for C(A(1,2)), the A(1,2) part is evaluated first to turn into 12, the two statements aren't equal like they would appear to be.

You can read more about these at cppreference.