C странный синтаксис макроса

Я нашел этот пример кода C, и я абсолютно озадачен:

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

Может кто-нибудь объяснить, что это должно делать? Он даже не компилируется в Visual Studio, но я запустил его онлайн (на ideone.com). ) и напечатал 2011, что также добавило путаницы.


person Eutherpy    schedule 01.05.2016    source источник
comment
Возможный дубликат Что делает C??!??! оператор делать?   -  person GSerg    schedule 02.05.2016
comment
Это из запутанного конкурса C?   -  person John Coleman    schedule 02.05.2016
comment
не могу объяснить, также не видел раньше. Он компилируется в osx/darwin/unix. К вашему сведению, первая строка оценивает и печатает 20, вторая строка 1, третья строка 1.   -  person user3078414    schedule 02.05.2016
comment
Возможный дубликат Почему int _$[:›=‹%-!.0,}; компилировать?   -  person GSerg    schedule 02.05.2016
comment
@GSerg: это диграфы, а не триграфы. Хотя они связаны, я не думаю, что это обман.   -  person dreamlax    schedule 02.05.2016
comment
@dreamlax Диграфы были также упомянуты, поэтому я подумал, что это подойдет.   -  person GSerg    schedule 02.05.2016
comment
На stackoverflow буквально каждый день спрашивают о диграфах. Я не понимаю, почему так много копий одного и того же вопроса попадает в списки горячих вопросов... или почему они не закрываются как дубликаты.BlueRaja - Дэнни Пфлюгхофт, 14 авг.   -  person cat    schedule 02.05.2016
comment
@GSerg Вопросы с большим количеством различных обфускаций, объединенных в одну слизь, довольно плохи для дубликатов. Скорее закройте тот как дубликат к этому.   -  person Lundin    schedule 02.05.2016


Ответы (1)


Он использует диграфы C, которые были поправками к стандарту C в 1994 году и, следовательно, частью стандарта C99. Заменив орграфы их реальными символами, вы получите:

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

Итак, имейте в виду, что a##b объединит входные данные в один идентификатор. Так как макросу только что переданы a и b, результатом будет только ab, поэтому вы фактически имеете:

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

Назначение c на самом деле не имеет значения, поэтому мы можем избавиться от него:

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

Теперь давайте избавимся от тернарного оператора (?:), потому что мы можем работать с ним статически (ab[a] всегда истинно, потому что a равно 1, а ab[1] равно 20, т. е. отлично от нуля):

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

Теперь замените переменные их фактическими значениями, т. е. ab[a] на 20 и a на 1.

main()
{
  int a=1, b=2, ab[]={10,20};
  printf( "%d", 20 );
  printf( "%d", 1 );
  printf( "%d", 1 );
}
person dreamlax    schedule 01.05.2016
comment
впечатляющий анализ - person John Coleman; 02.05.2016
comment
Ничего себе, это открывает целый новый мир возможностей. :D Спасибо! - person Eutherpy; 02.05.2016
comment
@Eutherpy: Нет. Нет. Сделай вид, что никогда этого не видел. - person John Bode; 02.05.2016
comment
@Eutherpy Диграфы и триграфы были действительно плохими идеями, которые были добавлены в стандарт для поддержки различных экзотических раскладок компьютерной клавиатуры по всему миру (вместо того, чтобы придумать стандарт ключевого слова). Они остались в прошлом, в настоящее время они считаются 100% плохой практикой. - person Lundin; 02.05.2016
comment
в эти дни они должны добавить аналогичную поддержку смайликов ???? - person Ciprian Tomoiagă; 02.05.2016