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;
}
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 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.
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.)
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.
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)
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.