3

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?

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Ahamed Yasir
  • 189
  • 1
  • 13
  • 1
    And what is the numeric value of `--5`? – Andrew Henle Jun 24 '18 at 11:38
  • The preprocessor does not combine tokens, so (in effect) adjacent `-` signs as a result of preprocessing have spaces between them `- - 5` (note the spaces) is equivalent to `-(-(5))`, which gives a result of `5`. – Peter Jun 24 '18 at 11:40
  • Possible duplicate of [Why is C/C++ preprocessor adding a space here?](https://stackoverflow.com/questions/31021711/why-is-c-c-preprocessor-adding-a-space-here) – Joy Allen Jun 24 '18 at 12:05

3 Answers3

7

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
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • So writing a new answer instead of linking to [the duplicate](https://stackoverflow.com/a/44934721/597607)? :-) But this answer is now much better than the old one. – Bo Persson Jun 24 '18 at 14:24
  • Yes, somehow the two questions and answers should be combined, please. – Jens Gustedt Jun 24 '18 at 15:51
1

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.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

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

Sahil Julka
  • 75
  • 1
  • 6