1

I am trying to understand how the next calculation is performed.

For example, if this is my terminal command

gcc ex2.c -D b+=2

Why do I get 5?

#include <stdio.h>

int main() 
{
#ifdef b
    printf("%d\n", 2 b | ~ 2 b);
#endif
    return 0;
}

2 b mean 2*b ?

~ 2 b mean 2*b and then ~ ?

user694733
  • 15,208
  • 2
  • 42
  • 68
Gi5
  • 83
  • 1
  • 7
  • 2
    This is ...weird....don't learn to write and execute code like this. – Sourav Ghosh Feb 18 '19 at 11:44
  • This is a question from a test that I did – Gi5 Feb 18 '19 at 11:50
  • 1
    According to [this page](https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html) `-D b+=2` doesn't seem like a valid syntax. – user694733 Feb 18 '19 at 11:53
  • 5
    I guess whoever gave the test is into Shakespeare ("2 b | ~ 2 b" is C for "to be, or not to be"). Fun, but also a bit annoying in a learning context, this is very contrived and in the real world programmers doing things like this are at high risk of getting ... words in a code review. – unwind Feb 18 '19 at 11:53

2 Answers2

7

This is weird that it works and looks like a bug (or feature) from gcc and clang in parsing command line arguments.

Looks like gcc substitutes the first = sign in macro declaration by a space. So the parameter:

-D b+=2

is equal to

#define b+ 2

which because gcc has an extension to interpret it like that, it is equal to

#define b + 2

which makes the preprocessor output:

printf("%d\n", 2 + 2 | ~ 2 + 2);

the expression 2 + 2 | ~ 2 + 2 is equal to (2 + 2) | ((~ 2) + 2) (see operator precedence) which on twos complement system is equal to 4 | (-3 + 2) which is equal to 4 | -1. On twos-complement -1 is equal to 0xff....ff so 4 | -1 is equal to 0xff...ff (as it is binary OR) which is -1.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • so for b+=3 i will get 5 ? – Gi5 Feb 18 '19 at 12:03
  • No idea, let's see: `2 + 3 | ~ 2 + 3` = `5 | -3 + 3` = `5 | 0` = `5`. Yea, you will get lucky `5`. – KamilCuk Feb 18 '19 at 12:04
  • Thank you very much my friend – Gi5 Feb 18 '19 at 12:07
  • 1
    This is really ugly. It also works with more complicated expressions, like `printf 'b\nb b\nb(3)' | gcc -E - -dD -D'b(=x)(x+x)'`. I hope no one uses this for practical programming, and I haven't even seen an IOCCC entry misusing this. – Roland Illig Feb 18 '19 at 12:20
  • 2
    I found [the GCC code doing this, in cpp_define](https://github.com/gcc-mirror/gcc/blob/e1b6ccb9e6bf0bf18f0b4154e16d3c5cdfab305e/libcpp/directives.c#L2377), it's exactly what you assumed. I didn't find a test case for this behavior though. – Roland Illig Feb 18 '19 at 14:02
  • 1
    And [the code for LLVM](https://github.com/llvm/llvm-project/blob/e88e2b99353fe50f7bcfe83436883a72f9fb8c54/clang/lib/Frontend/InitPreprocessor.cpp#L38). Also no mention about the feature misused in this question. – Roland Illig Feb 18 '19 at 14:29
4

compiling with gcc ex2.c -D b+=2 define b as +2 so the source

#include <stdio.h>

int main() 
{
#ifdef b
    printf("%d\n", 2 b | ~ 2 b);
#endif
    return 0;
}

is like

#include <stdio.h>

int main()
{

    printf("%d\n", 2 + 2 | ~ 2 + 2);

    return 0;
}

and for me that prints -1


to see the result after the preprocessing use the option -E :

/tmp % gcc ex2.c -E -D b+=2
<command-line>: warning: missing whitespace after the macro name
...
# 2 "ex2.c" 2

int main()
{

    printf("%d\n", 2 + 2 | ~ 2 + 2);

    return 0;
}
bruno
  • 32,421
  • 7
  • 25
  • 37
  • so the ' ~ ' operator is on 2 or 2+2 ? – Gi5 Feb 18 '19 at 11:54
  • @GiladRozmarin it is on _2_ because of the operator precedence, in both case the result is -1 because put all the bits to 1 – bruno Feb 18 '19 at 11:59
  • it was by mistake – Gi5 Feb 18 '19 at 12:06
  • @GiladRozmarin do not forget the option `-E` it is useful to understand what appends, you can put in comment some #include before to use it to not have plenty lines produced – bruno Feb 18 '19 at 12:08