доведем задачу до абсурда
По-моему у вас получилось. Почему 0x17? Из-за 0x0b?
Ничем специальным число не обусловлено. Просто генератор выдал именно 0x17 и дальше пошло-поехало.
Блин, уже на втором примере сломал мозг…
Хочу поставить 0х17 лайков. Но с пояснениями статья была бы намного интереснее и полезнее.

Второй пример сильно попахивает неопределённым поведением и индексацией случайных адресов памяти. Или я неправ?
Нет, UB нет ни в одном из примеров.
Я обдумывал идею добавить разборы, но они сделали бы статью существенно скучнее. В итоге решил оставить без пояснений, благо комментарии позволяют обсудить конкретные места.

Нет. (!true)["true"] — это то же самое что "true"[0], т.е. символ 't'. Со второй частью аналогично.

Вроде как ptr[n] == n[ptr], то есть это выражение эквивалентно ('t' -'F') >> 1 => 0x2e >> 1 => 0x17
Здесь всё в порядке: x[y] раскрывается в *(x + y).
Да, дошло через 5 минут модификаций кода в ideone, чтоб понять, что же он делает. А комментарий ни добавить, ни отредактировать уже не мог. В общем, надо сначала подумать, а потом уже в комментариях спрашивать :)

Только насчёт x + y не согласен, потому что здесь это явно раскрылось в y+x. Арифметика указателей разве коммутативна?
Коммутативна для байт, на этом и построен трюк 3[«test»] == «test»[3]

Что такое "коммутативна для байт"??? О_о

Коммутативность не имеет никакого отношения к "арифметике указателей". Коммутативен встроенный бинарный оператор + и коммутативен абсолютно всегда, безусловно и во всех контекстах.

Я о том, что совершенно не очевидно, что int + char* — такая же валидная операция, как char* + int. Более того: возможно, даже, имело бы смысл сделать первый вариант синтаксической ошибкой.

Я не вижу никакой опасности в такой коммутативности. А запрещать чисто ради запрещения в С не принято.

Простите, но там в начале разве должна быть O (буква) или все же 0 (цифра)?


int Ox01 = ~-~-~-~-~-~-~-~-~-' ';
Названия переменных же нельзя начинать с цифры. Вот и выкрутились
Точно, не заметил что это название переменной.
Есть еще сильно подгонный вариант (по сути будет работать только в вашем примере на Ideone, и может еще на других 64 битных машинах с linux, gcc 6.3 и использующих ту же версию libc) — в глобальных переменных обьявить extern «C» void _start(); (в случае чистого C — просто extern) а непосредственно в main int Ox18 = ~((char*)_start)[142];
В некоторых промежуточных версиях у нас были подобные варианты, например, через отрицательные индексы массивов, но в итоге, от них решили отказаться, поскольку они очень ненадежные.
Вообще говоря общая идея — это использовать оп код вызова call x86 ассемблера, я пока думаю как это можно сделать 100% предсказуемым образом.
P.S сори, промахнулся веткой :(
Нумерация OxZZ не с нуля — вся статья на выброс.
Ну хоть кто-то заметил, а я уже начал терять веру в людей.
Разве это не было сделано, что бы последняя переменная было с номером 0x17?
Примерно так. Но даже если бы отсчет шел с Ox00 по Ox16 общее количество в 0x17 все равно было бы очевидно.

Во-первых, ваши решения написаны не на С, а на GCC, да и те платформеннозависимы. Такие задачи интереснее решать именно на стандартном С. Ваши решения в большинстве своем к С относятся мало или вообще никак.


Во-вторых, ideone в профессиональных кругах не считается уважаемым или убедительным ресурсом, особенно в вопросах С, поэтому заявления вида "для сомневающихся — ссылка на ideone" никаких сомнений не развеивают, а могут вызвать лишь facepalm.

А можно аргументы?

Запросто!


На "во-первых" аргументы очевидны: большинство вариантов завязаны на свойство платфоременно-зависимого character set. Вот и все. К тому же фактически способов что-то сделать у вас от силы три. И один из них — применение * к строковому литералу — раздут в огромное число вариантов. Зачем было делать искусственное и скучное раздувание этих способов в такое количество уныло повторяющихся вариантов — не ясно. Это же сразу бросается в глаза.


Найти остроумные решения, которые бы работали на настоящем стандартном С — вот это действительно интересная задача, потому что в ней заключается challenge. А ваши чисто косметические выверты на фактически готовеньком результате (т.е. на конкретных значениях character constants) — примитивная пустышка/профанация для студенток-первокурсниц.


На "во-вторых" аргументы тоже несложны: хорошо известно, что ideone занимается наглой пост-фильтрацией диагностических сообщений компилятора. Не видя стандартных диагностических сообщений компилятора рядовой пользователь не сможет судить о корректности кода. Ваш код грубо ошибочен, но тем не менее проглатывается ideone — вескость этого аргумента переоценить невозможно.


Например, для использования true и false обязательно требуется включение <stdbool.h>. Для использования compl и xor обязательно требуется включение <iso646.h>. У вас же ideone в режиме С (!) проглотил это все даже не поперхнувшись. Именно по таким причинам в темах по языку С не принято оскорблять присутствующих ссылками на потешные глюкала типа ideone. Возмите в привычку пользоваться общепризнанными стандартами типа coliru. Какой бы вы ресурс не использовали, контроль над командной строкой компилятора — обязателен.


P.S. Ой, только что обратил внимание! Вы вообще в С++ это все компилировали! Так зачем же вы нам тогда баки забиваете какими то сказками про "практику программирования на C"?

А я все думал, когда же вы заметите про c++.
Я себе ограничений в «чистый си, где даже даже в ASCII нельзя быть уверенным» не ставил.
Произошло ровно то, что написано в статье — мой код оскорбил практики программирования на си.

На С++ все даже хуже, ибо в С++ символьная константа имеет тип char, а не int. И это значит, что в С++ все ваши символьные константы будет подвергаться integral promotions, которые, в зависимости от платформы, могут превратить ее в int или в unsigned int. Вариант с unsigned int — целый ящик Пандоры самостоятельных проблем. (Хотя аналогичные проблемы с integral promotions присутствуют в этом коде и с точки зрения С).

Тем не менее, используемый character set не является чем-то уникальным для GCC, так что ваше утверждение «решения написаны на GCC» все еще странное.

Это не принципиально. Завязка на character set в решении таких задач — это совершенно неинтересный читинг. А тут еще 90% приведенных "решений" — унылое повторение снова, снова и снова одного и того же приема с *"строка", к тому же завязанного на character set.

избавляться мы будем от магического числа 0x17.

Вот это мне повезло!
Я был близок!
На картинке для кликбайта написано 0x17 а в решениях совсем другое
int Ox07 = '.'>>!false;
int Ox17 = 010-001+010+010;
какая то даже не пятничная статья
Только полноправные пользователи могут оставлять комментарии.
Войдите, пожалуйста.