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;
}
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;
}
No need to compile this code, just use
gcc -E
on it (preprocessor) and see what happens: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.)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.
is the environment in the moment when
A
is evaluated. Now, making the evaluation process ofA
, we haveand this one will not be evaluated any more by the Prosser's algorithm, as it has no more identifiers.
So, reducing,
the stream
A
is converted in the stream5
and this one will be converted from preprocessing tokens in C-tokens and sent further to the C compiler.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:
is first translated into (A becomes -B):
then into (B becomes -C);
and then into (C becomes 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.
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:But the two
-
are separate tokens, so depending if the preprocessor separates them in its output or not, you may get a program that outputs5
or one that does not compile because--
cannot be applied to a literal5
.Both the
gcc
and theclang
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>
: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.
This an excellent example how do not use the preprocessor. To avoid confusions parenthesis should be used (not only in this case)