Why these consecutive macro replacements do not re

2020-04-11 06:03发布

This program gives output as 5. But after replacing all macros, it would result in --5. This should cause an compilation error, trying to decrement the 5. But it compiles and runs fine.

#include <stdio.h>
#define A -B
#define B -C
#define C 5

int main()
{
    printf("The value of A is %d\n", A); 
    return 0;
} 

Why is there no error?

标签: c macros
3条回答
Root(大扎)
2楼-- · 2020-04-11 06:38

Here are the steps for the compilation of the statement printf("The value of A is %d\n", A);:

  • the lexical parser produces the preprocessing tokens printf, (, "The value of A is %dn", ,, A, ) and ;.
  • A is a macro that expands to the 2 tokens - and B.
  • B is also a macro and gets expanded to - and C.
  • C is again a macro and gets expanded to 5.
  • the tokens are then converted to C tokens, producing errors for preprocessing tokens that do not convert to proper C tokens (ex: 0a). In this example, the tokens are identical.
  • the compiler parses the resulting sequence according to the C grammar: printf, (, "The value of A is %d\n", ,, -, -, 5, ), ; matches a function call to printf with 2 arguments: a format string and a constant expression - - 5, which evaluates to 5 at compile time.
  • the code is therefore equivalent to printf("The value of A is %d\n", 5);. It will produce the output:

    The value of A is 5
    

This sequence of macros is expanded as tokens, not strictly a sequence of characters, hence A does not expand as --5, but rather as - -5. Good C compilers would insert an extra space when preprocessing the source to textual output to ensure the resulting text produces the same sequence of tokens when reparsed. Note however that the C Standard does not say anything about preprocessing to textual output, it only specifies preprocessing as one of the parsing phases and it is a quality of implementation issue for compilers to not introduce potential side effects when preprocessing to textual output.

There is a separate feature for combining tokens into new tokens in the preprocessor called token pasting. It requires a specific operator ## and is quite tricky to use.

Note also that macros should be defined with parentheses around each argument and parentheses around the whole expansion to prevent operator precedence issues:

#define A  (-B)
#define B  (-C)
#define C  5
查看更多
倾城 Initia
3楼-- · 2020-04-11 06:41

Whenever we use #include in C program, compiler will replace the variable with its value wherever it is used.

#define A -B
#define B -C
#define C 5

So when we print A , it will execute in following steps.

A=>-B

B=>-C

A=>-(-C)=>C

So when we print value of A, it comes out to be 5.

Generally these #define statements are used to declare value of constants that are to be used through out the code.

For more info see this link on #define directive

查看更多
够拽才男人
4楼-- · 2020-04-11 06:47

Two consecutive dashes are not combined into a single pre-decrement operator -- because C preprocessor works with individual tokens, effectively inserting whitespace around macro substitutions. Running this program through gcc -E

#define A -B
#define B -C
#define C 5

int main() {
    return A;
}

produces the following output:

int main() {
    return - -5;
}

Note the space after the first -.

According to the standard, macro replacements are performed at the level of preprocessor tokens, not at the level of individual characters (6.10.3.9):

A preprocessing directive of the form

# define identifier replacement-list new-line

defines an object-like macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.

Therefore, the two dashes - constitute two different tokens, so they are kept separate from each other in the output of the preprocessor.

查看更多
登录 后发表回答