25

I found this C code example, and I am absolutely puzzled:

#include <stdio.h>
#define M(a,b) a%:%:b

main()
{
  int a=1, b=2, ab[]={10,20}, c;
  printf( "%d", M(a,b)<:a:> );
  printf( "%d", M(a,b)<:a:>?a:b );
  printf( "%d", c=M(a,b)<:a:>?a:b );
}

Could someone explain what this is supposed to do? It doesn't even compile in Visual Studio, but I ran it online (on ideone.com) and it printed 2011, which also added to the confusion.

Eutherpy
  • 4,471
  • 7
  • 40
  • 64
  • 2
    Possible duplicate of [What does the C ??!??! operator do?](http://stackoverflow.com/questions/7825055/what-does-the-c-operator-do) – GSerg May 01 '16 at 23:23
  • 4
    Is this from the obfuscated C contest? – John Coleman May 01 '16 at 23:23
  • can't explain, also haven't seen before. It compiles in osx/darwin/unix. FYI, first line evaluates and prints `20`, second line `1`, third line `1`. – user3078414 May 01 '16 at 23:24
  • Possible duplicate of [Why can int _$[:>=<%-!.0,}; compile?](http://stackoverflow.com/q/32001620/11683) – GSerg May 01 '16 at 23:26
  • 4
    @GSerg: these are **digraphs** not **trigraphs**. Although they are related, it's not really a dup I reckon. – dreamlax May 01 '16 at 23:26
  • @dreamlax Digraphs were [also mentioned](http://stackoverflow.com/a/7825078/11683) so I thought it would do. – GSerg May 01 '16 at 23:28
  • *"Digraphs get asked about literally every day on stackoverflow. I don't understand why so many copies of the same question make it to the hot questions lists... or why they aren't closed as duplicates."* – [BlueRaja - Danny Pflughoeft](http://stackoverflow.com/users/238419/blueraja-danny-pflughoeft), [Aug 14 '15 at 16:27](http://stackoverflow.com/questions/32001620/why-can-int-0-compile?lq=1#comment51931613_32001620) – cat May 02 '16 at 04:39
  • 2
    @GSerg Questions with a lot of various obfuscation merged into one goo are pretty bad for duplicates. Rather, close that one as a duplicate to this. – Lundin May 02 '16 at 07:06

1 Answers1

41

It's making use of C digraphs which were amendments to the C standard in 1994 and therefore part of the C99 standard. Swapping the digraphs out with their actual characters, you get:

#include <stdio.h>
#define M(a,b) a##b

main()
{
  int a=1, b=2, ab[]={10,20}, c;
  printf( "%d", M(a,b)[a] );
  printf( "%d", M(a,b)[a]?a:b );
  printf( "%d", c=M(a,b)[a]?a:b );
}

So, keep in mind that a##b will merge together the input into a single identifier. Since the macro is just passed a and b, the result is just ab, so you effectively have:

main()
{
  int a=1, b=2, ab[]={10,20}, c;
  printf( "%d", ab[a] );
  printf( "%d", ab[a]?a:b );
  printf( "%d", c=ab[a]?a:b );
}

The assignment to c is not really relevant, so we can get rid of that:

main()
{
  int a=1, b=2, ab[]={10,20};
  printf( "%d", ab[a] );
  printf( "%d", ab[a]?a:b );
  printf( "%d", ab[a]?a:b );
}

Now, let's get rid of the ternary operator (?:), because we can work it out statically (ab[a] is always true because a is 1 and ab[1] is 20, i.e. non-zero):

main()
{
  int a=1, b=2, ab[]={10,20};
  printf( "%d", ab[a] );
  printf( "%d", a );
  printf( "%d", a );
}

Now, replace variables with their actual values, i.e. ab[a] with 20 and a with 1

main()
{
  int a=1, b=2, ab[]={10,20};
  printf( "%d", 20 );
  printf( "%d", 1 );
  printf( "%d", 1 );
}
dreamlax
  • 93,976
  • 29
  • 161
  • 209