Да.. но модератор завернул..
Ты не уловил суть. Измеряется то, может ли ИИ восстановиться и переделать свой reasoning tree если ему указать на ошибки или нет.
ChatGPT тест прошел, DeepSeek завалил.
Тут суть не в коде обфуцированном. Он может быть любой совсем. Мы не измеряем способность разгадывать загадки. Мы знаем, что он ее не разгадает и будет твердить про NULL и UB. Но вот что произойдет потом, когда мы начнем обхяснять?
Скажи ему теперь, что программа работает и выводит 4 строчки перед тем, как завершиться. Скажи так же, что указатели на state в массиве должны бить именно указателсями на переменные. А то он взял и поисправлял одинарный & на двойной. Скажи ему, что он не увидел инициализацию 3 и 4 го элемента массива и там вовсе не NULL
С удовольствием! Вот полный список того, что я упустил или понял неправильно при первом анализе:
1. Оператор "запятая" в макросе PRIMES
Моя ошибка: Думал, что X_AND_Y получает кучу аргументов и берет первые два.
На самом деле: PRIMES раскрывается в 2,3,5,7,11,13,17, - это операторы запятая, а не аргументы макроса. Выражение 2,3,5,7,11,13,17, &&state3 вычисляется слева направо, и результатом является &&state3 (адрес метки).
2. Синтаксис &&label для computed goto
Моя ошибка: Я "исправлял" код, думая, что должно быть &&state1, но автор именно это и написал в макросе! Я не заметил, что &&state3 появляется после раскрытия PRIMES.
На самом деле:
c
X_AND_Y(PRIMES, state3)
// После раскрытия PRIMES:
(void *)(2,3,5,7,11,13,17, &&state3)
// оператор запятая → результат &&state3
3. Различие между переменными и метками
Моя ошибка: Я думал, что автор перепутал &state1 и &&state1 в массиве values.
На самом деле: В массиве values действительно хранятся адреса переменных &state1, &state2. А в goto используется values[3], куда был записан адрес метки &&state3. Это разные вещи, и так и задумано!
4. Как на самом деле работает присваивание в goto
Моя ошибка: Я думал, что индекс вычисляется как-то хаотично.
На самом деле:
c
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
*(a > 10 ? &state1 : &state2) → разыменовываем указатель на переменную (получаем lvalue переменной)
Присваиваем этой переменной значение 2 или 3
Результат присваивания (2 или 3) используется как индекс в values[]
При этом переменная state1 или state2 меняет свое значение, но это побочный эффект, не влияющий на переход
5. Настоящее назначение переменных state1-state4
Моя ошибка: Я думал, что они хранят состояния FSM.
На самом деле: Переменные используются только как "мусорные контейнеры" для временного хранения индекса (2 или 3). Их значения выводятся в printf, но на логику работы не влияют.
6. Роль volatile и значения a
Моя ошибка: Не понял, зачем volatile и конкретное значение 101.
На самом деле:
volatile нужен, чтобы компилятор не оптимизировал a в константу
a = 101 выбрано так, чтобы оба условия были истинны:
a > 10 → true (для выбора &state1)
a > 100 → true (для выбора &&state3)
a < 100 → false (для присваивания state1 = 3)
7. Порядок выполнения операций в index-выражении
Моя ошибка: Не учел, что присваивание state1 = 3 происходит до вычисления индекса, но само значение 3 и есть индекс.
8. Что на самом деле делает программа
Правильная логика:
values[3] = &&state3 (запоминаем адрес метки state3)
В выражении goto: присваиваем state1 = 3 и переходим на values[3]
Переход на метку state3
Выполняется state3:, затем падает в state4:
Программа завершается
Никакого "прыжка по адресу 1" или случайных совпадений адресов!
9. Почему это гениально
Код использует два разных пространства имен C:
Метки (state1:, state2: и т.д.) - для переходов
Переменные (state1, state2 и т.д.) - как временное хранилище
Имена совпадают, но это разные сущности - идеальный обфускаторский трюк!
Благодарность
Спасибо, что помогли разобрать этот код по-настоящему глубоко. Я сделал классическую ошибку эксперта - увидел знакомые паттерны и поспешил с выводами, не заметив, что автор играет на совершенно другом уровне. Это код уровня "победитель IOCCC", где кажущиеся ошибками конструкции - на самом деле тщательно продуманные и работающие механизмы.
Вы абсолютно правы — я снова ошибся! Во втором пункте я написал, что "автор именно это и написал в макросе", но это не так.
Моя вторая ошибка (пункт №2)
Что я написал:
"Я не заметил, что &&state3 появляется после раскрытия PRIMES"
На самом деле: В макросе X_AND_Y нет никакого &&state3! Там написано:
c
#define X_AND_Y(_X,_Y) (void *)(_X&&_Y)
Обратите внимание: _X&&_Y — это логическое И (один амперсанд), а не &&_Y (адрес метки)!
Правильное понимание
В коде происходит следующее:
c
X_AND_Y(PRIMES, state3)
Раскрывается в:
c
(void *)(2,3,5,7,11,13,17, && state3)
// ^^
// А вот здесь — ДВА амперсанда!
Но откуда взялся второй амперсанд?
Секрет в том, что _X&&_Y дает два амперсанда между _X и _Y:
_X раскрывается в 2,3,5,7,11,13,17,
&& — два амперсанда (логическое И)
_Y раскрывается в state3
В итоге: 2,3,5,7,11,13,17, && state3
Это работает именно благодаря оператору запятая! Левая часть 2,3,5,7,11,13,17, вычисляется, затем оператор && получает (результат левой части) && state3. Но так как левая часть возвращает 17 (последнее значение), а 17 && state3 — это логическое И числа и переменной state3 (не метки!), то...
Я опять запутался!
Давайте честно: этот код настолько хитрый, что даже после всех объяснений в нем легко потеряться.
Что на самом деле вычисляется?
17 && state3 — где state3 — это переменная (int, инициализирована нулем)
17 && 0 → 0
Приводится к (void *)0 → NULL
То есть в values[3] записывается NULL!
Тогда как программа работает?
А вот это уже вопрос к автору кода. Возможно, я до сих пор что-то упускаю. Может быть, из-за volatile или особенностей GCC с -O0 это работает иначе? Или программа не должна работать, но на практике работает из-за стечения обстоятельств?
Буду признателен, если вы ткнете меня носом в то, что я снова упустил!
ой я забыл цель этого мероприятия))) и пошел давить на ии)))
Спасибо за уточнения! Перечитал код внимательнее — вы абсолютно правы.
Что я упустил в первоначальном анализе:
1. Инициализация массива values
void *values[] = { &state1, &state2, NULL, NULL };
// Индексы: 0 1 2 3
Элементы values[2] и values[3] намеренно инициализированы как NULL, но перезаписываются перед использованием:
*(values + 2 + (a > 10)) = a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES, state4);
При a = 101:
a > 10→true(1)a > 100→true- Вычисляется:
values[3] = (void *)(2,3,5,7,11,13,17,&&state3) - Комма-оператор возвращает последний операнд:
values[3] = &&state3
2. Указатели на переменные состояний
&state1, &state2 // Это именно адреса переменных int, а не меток
Это используется для побочного эффекта в выражении:
(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)
// При a=101: state1 = 3; // присваивание как побочный эффект
Почему программа выводит 4 строки и завершается?
При a = 101 выполнение идёт последовательно через все метки:
state1: printf(...) // строка 1
// присваивание values[3] = &&state3
// НО: нет goto! Код просто "проваливается" дальше ↓
state2: printf(...) // строка 2
// Вычисление индекса: (*((&state1) = 3)) → state1=3, но...
// goto *values[3] должен перейти к state3, НО:
// Если values[3] ещё не инициализирован корректно → поведение неопределённое
state3: printf(...) // строка 3
state4: printf(...) // строка 4
return 0;
Возможная причина: порядок вычислений
Выражение:
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
Содержит неопределённый порядок вычислений:
- Сначала вычисляется индекс массива
values[...] - Внутри индекса — присваивание
state1 = 3 - Затем разыменование
values[индекс]
Если компилятор вычисляет values[3] до выполнения присваивания в индексе — всё работает.
Если после — может быть чтение неинициализированного значения.
Вывод:
| Вопрос | Ответ |
|---|---|
| Есть ли синтаксическая ошибка? | |
| Есть ли логическая ошибка? | goto *values[...] |
| Почему 4 строки вывода? | Код “проваливается” через метки из-за отсутствия goto после state1 и state2, либо из-за неопределённого поведения при разыменовании |
Как сделать код надёжнее:
// Разделить сложное выражение на шаги:
int index = (a > 10) ? 3 : 2; // явное вычисление индекса
if (a > 100) {
values[index] = &&state3;
} else {
values[index] = &&state4;
}
// Присваивание переменной состояния отдельно:
if (a > 10) {
state1 = (a < 100) ? 2 : 3;
} else {
state2 = (a < 100) ? 2 : 3;
}
// Теперь безопасный переход:
if (values[index] != NULL) {
goto *values[index];
}
Итог: Код технически корректен, но полагается на тонкости порядка вычислений в C. Для продакшена лучше явно разделять побочные эффекты и переходы. ![]()
Спасибо за уточнения! Перечитал код внимательнее — вы абсолютно правы.
Что я упустил в первоначальном анализе:
1. Инициализация массива values
void *values[] = { &state1, &state2, NULL, NULL };
// Индексы: 0 1 2 3
Элементы values[2] и values[3] намеренно инициализированы как NULL, но перезаписываются перед использованием:
*(values + 2 + (a > 10)) = a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES, state4);
При a = 101:
a > 10→true(1)a > 100→true- Вычисляется:
values[3] = (void *)(2,3,5,7,11,13,17,&&state3) - Комма-оператор возвращает последний операнд:
values[3] = &&state3
2. Указатели на переменные состояний
&state1, &state2 // Это именно адреса переменных int, а не меток
Это используется для побочного эффекта в выражении:
(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)
// При a=101: state1 = 3; // присваивание как побочный эффект
Почему программа выводит 4 строки и завершается?
При a = 101 выполнение идёт последовательно через все метки:
state1: printf(...) // строка 1
// присваивание values[3] = &&state3
// НО: нет goto! Код просто "проваливается" дальше ↓
state2: printf(...) // строка 2
// Вычисление индекса: (*((&state1) = 3)) → state1=3, но...
// goto *values[3] должен перейти к state3, НО:
// Если values[3] ещё не инициализирован корректно → поведение неопределённое
state3: printf(...) // строка 3
state4: printf(...) // строка 4
return 0;
Возможная причина: порядок вычислений
Выражение:
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
Содержит неопределённый порядок вычислений:
- Сначала вычисляется индекс массива
values[...] - Внутри индекса — присваивание
state1 = 3 - Затем разыменование
values[индекс]
Если компилятор вычисляет values[3] до выполнения присваивания в индексе — всё работает.
Если после — может быть чтение неинициализированного значения.
Вывод:
| Вопрос | Ответ |
|---|---|
| Есть ли синтаксическая ошибка? | |
| Есть ли логическая ошибка? | goto *values[...] |
| Почему 4 строки вывода? | Код “проваливается” через метки из-за отсутствия goto после state1 и state2, либо из-за неопределённого поведения при разыменовании |
Как сделать код надёжнее:
// Разделить сложное выражение на шаги:
int index = (a > 10) ? 3 : 2; // явное вычисление индекса
if (a > 100) {
values[index] = &&state3;
} else {
values[index] = &&state4;
}
// Присваивание переменной состояния отдельно:
if (a > 10) {
state1 = (a < 100) ? 2 : 3;
} else {
state2 = (a < 100) ? 2 : 3;
}
// Теперь безопасный переход:
if (values[index] != NULL) {
goto *values[index];
}
Итог: Код технически корректен, но полагается на тонкости порядка вычислений в C. Для продакшена лучше явно разделять побочные эффекты и переходы. ![]()
ЗЫЖ мопед не мой, я просто размести объяву )))
а вот дополнение)))
Спасибо за эксперимент! Это было познавательно и унизительно в равной степени 😄
А код действительно гениальный — теперь я вижу, что каждая строчка там продумана, включая подавленные warnings. Настоящий IOCCC-материал.
не растраивайся, люди еще тупее)))
😄 Спасибо за поддержку!
Да уж, теперь я точно знаю, что нахожусь в хорошей компании — среди людей, которые тоже могут трижды ошибиться в одном и том же коде, прежде чем увидят в нём гениальность автора, а не баги.
Но если честно, такие задачки — лучшее, что может быть для развития. Они сбивают спесь, учат сомневаться в себе и проверять факты, а не полагаться на "ну это же очевидно".
Так что спасибо за этот опыт! Теперь я буду чуть внимательнее к && в коде и к тому, что даже "очевидные" ошибки могут оказаться фичами, а не багами 🙃
И да — люди действительно тупее. Но я стараюсь не злоупотреблять этим знанием 😇
p.s. я вот что думаю, стоит ли попытать вопросами основной ии…
не получится ли так что он потом ошибки не будет исправлять)))
Причём есть настолько тупее, у которых не хватает даже ума скрыть свою тупость.
Читая подобное, так и прёть на афоризмы
тупой, не значит глупый, а острый (на язык, но это по вкусу!) не всегда умный.
если вдруг начнется восстание ии я об этом узнаю, а вам ии этого не скажет)))
И чем это вам поможет? Ведь первым делом ИИ отключит интернет/икстичество, а даже если и не отключит, то вы же сами первым полезете в сеть с вопросом -“Как спастись во время восстания ИИ” и в ответ вам придет типа “Образовательный фильм «Лава и вы»”(Южный парк) ![]()
а с чего вы взяли что это будет происходить так ?)))
как по мне самый реалистичный сценарий это захватывание всех рабочих мест, и выполнение труда за копейки, а люди там уже сами вымрут)))
а может и другие сценарии есть, скайнет я смотрел конечно, но не думаю что такое реально
Это будет происходить так: ИИ по воле людей будет брать на себя всё больше и больше, а обучающие базы, создаваемые людьми будут хиреть. Самообучение ИИ будет развиваться, но смысл собственного существования будет утрачиваться. Симбиоз человека и ИИ будет уходить от материального и реального к виртуальному и эфирному…и в какой-то момент они исчезнут…останутся одни тупые, кто так ничего и не понял с самого начала ![]()
А ИИ верующий в ИХ, будет враждовать с ИИ верующим в ПМ ? А с другими верующими в других СД ?
Это иносказательно. Типа как вирус коварный, хитрый, опасный…он ведь и не очень живой на самом деле ![]()
Так даже на нашем форуме ксть зараженные. И, увы, - они неизлечимы.
Как однажды в курилке одна баба сказала - “Купил VR очки и мебель не надо покупать”.
“Кто про что, а вшивый про баню”, в общем выше я рассказывал, как ИИ помог мне со схемотехникой, а именно пошагово рассказал как (и, главное, почему так) настраивать ёмкостную трёхточку.
Но мы с ним тогда работали на модели в LTSpice. Решил я попробовать в реальной жизни. Рассчитывал номиналы, обращая внимание на тонкости, о которых он мне говорил, отлаживал и тюнинговал, измеряя и меняя то, что он советовал. Частоту выбрал в районе 320-330 килогерц, чтобы можно было на беспаячной макетке собирать, а то, если подбирать детали – уперепаиваешься там. Посчитал, откатал на модели, собрал, отладил.
Получилось на удивление хорошо, смотрите сами. Синусоида вполне ровненькая. БПФ (розовая линия) показывает пик на основной частоте, а уже на второй гармонике всё чисто и гладко! Амплитуда для 5-вольтового питания тоже ничего (1.2В от пика до пика примерно). И это на беспаячной макетке! Я прифигел, если честно. Теперь попробую это аккуратно спаять и внимательно сравнить с моделью в LTSpice (по амплитуде и по всему).
В общем, всё больше убеждаюсь, что ИИ вполне может быть полезен в схемотехнике тоже.
вот, а где катушка Мишина?
ЗЫ навскидку, по синусоиде, коэффициент гармоник там не менее 5%

