Understanding macros in C [duplicate]

2019-04-26 16:52发布

This question already has an answer here:

Why is the output from the following code the value 5?

#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;
}

5条回答
看我几分像从前
2楼-- · 2019-04-26 17:24

No need to compile this code, just use gcc -E on it (preprocessor) and see what happens:

<lots of output expanding stdio.h> ...

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

Obviously the result is 5 (which could have been guessed by looking at the nested macros, but a small preprocessor test doesn't hurt).

(Other answers noted that some compilers may handle the preprocessing of the minus signs which would result in a compiler error. gcc handles that nicely.)

查看更多
Fickle 薄情
3楼-- · 2019-04-26 17:25

each #define preprocessing directive will insert in the environment of the preprocessor a variable assigned to a value made of a list of preprocessing directives.

{A -> -B; B->-C; C->5}

is the environment in the moment when A is evaluated. Now, making the evaluation process of A, we have

  A  ->  -B   (the identifier `A` is transformed in the stream of preprocessing tokens `-B`)
 -B  ->  --C
--C  ->  --5
->  5

and this one will not be evaluated any more by the Prosser's algorithm, as it has no more identifiers.

So, reducing,

 A->5

the stream A is converted in the stream 5 and this one will be converted from preprocessing tokens in C-tokens and sent further to the C compiler.

查看更多
Bombasti
4楼-- · 2019-04-26 17:31

Question doesn't really make sense, but I still decided to give it a go.

Visual Studio 2013 and 2015: error C2105: '--' needs l-value

Reason is that the following line:

printf("The value of A is %d\n", A);

is first translated into (A becomes -B):

printf("The value of A is %d\n", -B);

then into (B becomes -C);

printf("The value of A is %d\n", --C);

and then into (C becomes 5):

printf("The value of A is %d\n", --5);

And since 5 is not an l-value, you cannot decrement it, hence the error. Seems quite logical, knowing the preprocessor will just do a simple string replace.

查看更多
时光不老,我们不散
5楼-- · 2019-04-26 17:37

This is a tricky question because it is a stress test for the compiler preprocessor.

Depending if the preprocessor is an integrated phase of the compiler or a separate program passing its output to the compiler via a file or a pipe and in this case whether it is careful enough to not perform erroneous token pasting, you may get the expected output: 5 or you may get a compilation error.

After the preprocessed contents of stdio.h, the source code expands to:

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

But the two - are separate tokens, so depending if the preprocessor separates them in its output or not, you may get a program that outputs 5 or one that does not compile because -- cannot be applied to a literal 5.

Both the gcc and the clang preprocessors behave correctly and separate the - with an extra space to prevent token pasting when they produce the preprocessor output with the -E command line option. They output this as preprocessed source code after the expansion of <stdio.h>:

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

Try your own compiler to check how it expands the source code. It seems Visual Studio 2013 and 2015 fail the test and reject the program with an error.

To makes things clear, I do not say the behavior of the program should depend on the compiler architecture. I was hoping at least one common C compiler would mishandle this conformance test. I am not surprised MS Visual Studio 2013 and 2015 fail this test.

The extra space in only needed in the textual output of the preprocessor. It does not matter if Visual Studio uses multiple separate phases or not, the source program is perfectly valid and their failure to compile it is a BUG.

查看更多
对你真心纯属浪费
6楼-- · 2019-04-26 17:48

This an excellent example how do not use the preprocessor. To avoid confusions parenthesis should be used (not only in this case)

#define A (-B)
#define B (-C)
#define C (5)
查看更多
登录 后发表回答