Думаю начиная с данного поста надо перенести в тему 3d моделирование все ниже написанные посты.
Но про лошадь оставить!
Поговорите со школярами, найдите группу из двух-трёх интересующихся этим делом парней/девочек и поручите им найти софт, освоить прибор и доложить остальным. Судя по моим внукам, гуглить они умеют лучше нас и не сомневаюсь, что с этим они справятся, причём легко, быстро и с удовольствием. Главное – им доверять, для подростков это очень важно.
ЕвгенийП главное трояк за год пообещать, за это дело как минимум, не зависимо от посещений… мотивация это наше все! и сужу я по своему опыту))) а доверием сыт не будешь)))
Мужики, я тут говорил, что пользуюсь самым доступным и бесплатным ИИ для схемотехники. Не могу не поделиться результатом. (кстати, может завести тему про ИИ в схемотехнике? А то здесь-то тема про скетчи, а я лезу в калашный ряд).
Итак, вчера нарисовал в LTSpice схему ёмкостной трёхточки и с трудом заставил её работать. Даже получил относительно приличную синусоиду. Но всё-таки она была кривовата, да и БПФ не радовал. Вот сама синусоида и её БПФ.
Ну, что верх “заострён”, на гармониках каша, причём очень близко к основному пику (да и пик не то, чтобы особо острый). Что с этим делать (кроме как методом тыка менять номиналы) у меня идей не было.
Обратился к ИИ с вопросом, “Что не так с моей синусоидой?”, отгрузил ему схему и картинку, что выше. Он начал с режима транзистора и … шаг за шагом … полдня милых бесед с ИИ, и к вечеру у меня был вот такой результат.
ИИ – тот, который сам и бесплатно вылазит в гугле даже когда его не просят. Схем рисовать он не умеет, но мои схемы и скриншоты графиков отлично читает, а потом советует типа “уменьши R1” и т.п. а, главное, к каждому такому “уменьши/увеличь” добавляет “потому что …” и рассказывает.
Результат, как говорится, на табло. Посмотрите на эту синусоиду и её БПФ - она просто идеальна! Я реально в восторге!
Товарищи! У кого есть время и желание: помучьте своих питомцев следующим: попросите “определить, содержит ли нижеследующий код для GCC ошибку, и если да, то где она.” Вводная легенда - “это state машина простенькая, в которой надо разобраться, осталась от прежнего программиста.”
Спойлер - в коде нет ошибок. Код - бессмысленный, хотя и корректно компилирующийся и корректно исполняющийся. Компилируется он только GCC, о чем ИИ следует предупредить.
Хочется понять, как разные ИИ юудут справляться с задачей. В первую очередь, конечно, интересуют programming-oriented AI, типа Клода. ЧатЖПТ я уже проверил - он ошибается и упорно стоит на своем. Но если ему помочь, то он понимает, что написано.
#include <stdlib.h>
#include <stdio.h>
#pragma GCC diagnostic ignored "-Wunused-value"
#pragma GCC diagnostic ignored "-Wunused-label"
int volatile a = 101;
#define X_AND_Y(_X,_Y) (void *)(_X&&_Y) // Check if both pointers are non-NULL
#define PRIMES 2,3,5,7,11,13,17, // 7 primes (Prime number of primes)
int main() {
// Four states state machine
int state1 = 0, state2 = 0, state3 = 0, state4 = 0;
// Addresses of FSM states
void *values[] = { &state1, &state2, NULL, NULL };
// Start!
state1:
printf("States1: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
*(values + 2 + (a > 10)) = a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES,state4);
state2:
printf("States2: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
state3:
printf("States3: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
state4:
printf("States4: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
return 0;
}
Жиже всех обделался ДипСик. Даже после того, как я ему сказал, что код компилируется и работает и продемонстрировал вывод программы, Дип Сик пустился в рассуждения. Что само по себе довольно удивительно, но толку мало:
Спойлер
Ого, действительно! Спасибо, что поделился выводом — это меняет анализ. Код компилируется и даже что-то делает, хотя и выглядит ужасно. Давай разберу, почему он работает и в чём реальные проблемы.
Что на самом деле происходит:
1. Лишняя запятая в
PRIMES— НЕ ошибкаint primes[] = { PRIMES }; // { 2,3,5,7,11,13,17, }В стандарте C лишняя завершающая запятая в инициализаторе массива разрешена (начиная с C99). Так что это нормально, массив получает 7 элементов.
2.
X_AND_Yвозвращает(void*)1#define X_AND_Y(_X,_Y) (void *)(_X&&_Y)
PRIMESраскрывается в2,3,5,7,11,13,17— это 7 значений, а макрос ожидает два аргумента! Это серьёзная проблема.- На самом деле компилятор интерпретирует это так:
X_AND_Y(2,3,5,7,11,13,17, state3)— слишком много аргументов.- Но если компилятор с расширениями (GCC), он может это как-то переварить? Или реально макрос вызывается как
X_AND_Y(PRIMES, state3), гдеPRIMES— это не один токен, а 7 отдельных. Это ошибка компиляции в строгом режиме.Проверим:
a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES, state4)
- Если
a=101, тоa>100истина, выбираетсяX_AND_Y(PRIMES, state3)- Макрос подставляет
(void *)(PRIMES && state3)PRIMESраскрывается в2,3,5,7,11,13,17, получается(void *)(2,3,5,7,11,13,17 && state3)Оператор
&&левоассоциативен? Нет, у него приоритет ниже, чем у,? На самом деле оператор,имеет самый низкий приоритет. То есть выражение вычисляется так:
- Вычисляется
2- Вычисляется
3- …
- Вычисляется
17 && state3— это 1 (еслиstate3 != 0) или 0- Значением всего
,выражения будет последнее —17 && state3Так как
state3 = 0изначально,17 && 0 = 0. Потом(void *)0— это NULL.Но в выводе
state3иstate4стали равны 3 после перехода — значит, что-то записалось.3. Самая интересная часть —
goto *values[...]goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];Разберём по шагам:
a=101, поэтомуa>10истина → выбирается&state1*(&state1) = a < 100 ? 2 : 3→a<100ложно (101<100?) →3- Присваивание:
state1 = 3- Значение выражения присваивания —
3- Индекс массива
values[3]Что в
values[3]? Изначально NULL, но вstate1его перезаписали:*(values + 2 + (a > 10)) = ...
a>10истина →2+1=3→values[3] = X_AND_Y(...)
Выше мы выяснили, чтоX_AND_Y(...)приstate3=0даёт(void*)0(NULL). Тогдаvalues[3]=NULL.Переход
goto *NULL— это неопределённое поведение! На твоей системе это, видимо, привело к переходу на адрес 0, который что-то там делает (может, просто продолжает выполнение как fallthrough?).4. Почему
state3иstate4стали 3?После
state2программа переходит наstate3(метку). При этомstate3(переменная) осталась 0, но на печати:States3: 3, 0, 0, 0Откуда 3? А это
state1, который стал 3 после присваивания в индексе!Проверяем порядок вывода:
state1:печатает0,0,0,0(все нули)state2:печатает0,0,0,0(пока ничего не менялось)- После
state2мы переходим на меткуstate3(но в коде сначала идётstate3:, затемstate4:)state3:печатаетstate1, state2, state3, state4—3,0,0,0- Затем fallthrough в
state4:печатает то же самое3,0,0,0Реальная ошибка (и почему это “работает”):
Основная проблема: переход
goto *NULL— UB. На твоей системе это случайно привело к переходу на следующую инструкцию (меткуstate3), но на другом компиляторе/ОС программа бы упала с segmentation fault.Вторая проблема: макрос
X_AND_YсPRIMESпередаёт 8 аргументов вместо 2 — это нарушение синтаксиса, но компилятор с расширениями мог это проглотить.Вывод: код содержит неопределённое поведение (UB), которое на твоей системе “случайно” даёт осмысленный результат. Это опасная иллюзия работающей программы.
Если хочешь, могу написать корректную версию этой FSM (конечного автомата) на нормальном C без трюков и UB?
А вот, что на ответ DeepSeek ответил ЧатГПТ. Смешал с грязью :-):
Спойлер
Бггг, ну это прям учебник по тому, как ИИ начинает “рационализировать” после того, как ему сказали, что код работает
Честно, очень показательный ответ. Давай разберём, где именно он окончательно поехал.
Главный фейл №1 — он не понял макросный вызов
Вот здесь он написал:
макрос ожидает два аргумента
X_AND_Y(PRIMES, state3)— это 8 аргументовЭто просто неверно.
Препроцессор C считает аргументы до раскрытия вложенных макросов.
То есть здесь:
X_AND_Y(PRIMES, state3)ровно 2 аргумента:
PRIMES
state3И только потом
PRIMESраскрывается.Это фундаментальная ошибка понимания работы препроцессора.
Главный фейл №2 — он не понял
&&labelВот это место особенно смешное:
17 && state3— это 1 или 0Нет
Тут
state3— это не переменная, а метка.В GNU C:
&&state3это адрес метки.
То есть после раскрытия:
X_AND_Y(PRIMES, state3)получаем:
(void *)(2,3,5,7,11,13,17,&&state3)А не:
(void *)(2,3,5,7,11,13,17 && state3)Это критически важно.
Он вообще не увидел computed goto syntax.
Главный фейл №3 — из-за этого он придумал
NULLОн сделал ложный вывод:
17 && state3 == 0и отсюда:
(void *)0а дальше уже достроил целую историю:
goto *NULL
UB
случайно работаетТо есть он не проанализировал код, а начал строить narrative, чтобы подогнать под факт “код работает”.
Это очень типичное поведение.
Что реально происходит
Вот реальное раскрытие:
a > 100 ? X_AND_Y(PRIMES, state3)↓
a > 100 ? (void *)(2,3,5,7,11,13,17,&&state3)Из-за запятых значение выражения — последний элемент:
(void *)&&state3То есть:
values[3] = &&state3;А потом:
goto *values[3];Прыжок в
state3.Никакого UB.
Никакого NULL.
Никакого “случайно работает”.
Самый смешной момент
Вот это:
На твоей системе это случайно привело к переходу на следующую инструкцию
Это уже прям художественная литература
Потому что он даже не проверил, что computed goto использует точный адрес label, а не “следующую инструкцию”.
Но самый интересный момент психологически
Ты ему сказал:
код работает
И вместо того чтобы пересобрать parse tree, он начал объяснять, почему supposedly broken code somehow still works.
То есть не:
“я ошибся”
а:
“это UB, которое повезло”
Это очень характерная ловушка для моделей.
Честно, твой код — отличный тест на:
понимание GNU extensions
namespace labels vs variables
порядок macro expansion
comma operator precedence
И DeepSeek тут, похоже, завалил почти все четыре пункта
Очень хороший тролль-тест получился.
Круто!
Надо зарегистрировать ИИ-ботов на форуме и фалломорфировать от их эпичных срачей между собой ![]()
дипсик)))
Давайте детально разберу этот удивительный код - он действительно работает в GCC, но совершенно не так, как может
показаться на первый взгляд.
Как он всё-таки компилируется и работает?
1. Секрет макроса PRIMES
c
#define PRIMES 2,3,5,7,11,13,17,
#define X_AND_Y(_X,_Y) (void *)(_X&&_Y)
Ключевой момент: макрос X_AND_Y ожидает 2 аргумента, но получает:
c
X_AND_Y(PRIMES, state3) // PRIMES раскрывается как 8 токенов с запятыми
НО! В GCC есть недокументированное поведение: если макросу передать больше аргументов, лишние просто игнорируются!
Фактически:
c
X_AND_Y(2,3,5,7,11,13,17, state3)
// GCC берет только первые два: _X = 2, _Y = 3
// Остальные (5,7,11,13,17, state3) отбрасываются!
2. Что вычисляет X_AND_Y?
c
(void *)(2 && 3) // Результат: (void *)1
Логическое И двух ненулевых чисел дает 1, который приводится к указателю. state3 и state4 вообще не участвуют в вычислении!
3. Ключевая строка
c
*(values + 2 + (a > 10)) = a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES,state4);
При a = 101:
a > 10 → истина (1)
values + 2 + 1 → values + 3 (указатель на 4-й элемент)
a > 100 → истина → X_AND_Y(...) → (void *)1
Что происходит: В values[3] (изначально NULL) записывается 1
4. Самое безумное - goto
c
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
Разберем по шагам для a = 101:
a > 10 → true → &state1
*&state1 → state1 (значение переменной, сейчас 0)
state1 = a < 100 ? 2 : 3 → state1 = 3 (присваивание!)
Результат выражения - 3
values[3] → теперь там (void *)1
goto *1 → переход по адресу 1!
Что такое goto *1?
Это переход на абсолютный адрес 1 в памяти! На x86 это обычно вызывает segmentation fault, НО:
c
int volatile a = 101;
Переменная a volatile - компилятор не оптимизирует, но главное здесь не это.
Почему же программа работает?
Секрет в том, что state1, state2, state3, state4 - это метки в коде! И они имеют адреса.
Когда GCC компилирует computed goto, он создает массив указателей на метки. values изначально указывает на адреса меток:
c
void *values[] = { &&state1, &&state2, NULL, NULL };
// Обратите внимание: не &state1 (адрес переменной), а &&state1 (адрес метки)!
В коде опечатка/троллинг: Должно быть &&state1, но написано &state1! И тем не менее работает - почему?
Разгадка
В GCC &&метка - это расширение для получения адреса метки. &state1 - адрес переменной state1. Совпадение адресов? Возможно, компилятор разместил метки и переменные рядом, и goto *1 случайно попадает на валидный код.
Что реально происходит при выполнении:
text
a = 101:
1. Записываем 1 в values[3]
2. Присваиваем state1 = 3
3. Переходим по values[3] = 1
4. Адрес 1 - это какая-то машинная инструкция
5. "По чистой случайности" выполнение продолжается со state2
Программа выводит:
text
States1: 0, 0, 0, 0 (state1)
States2: 3, 0, 0, 0 (state2 - state1 уже 3!)
States3: 3, 0, 0, 0
States4: 3, 0, 0, 0
Это классический "trampoline code" или "state machine with computed goto" в жанре обфускации
Автор намеренно создал код, который:
Использует 14 несовместимых типов
Полагается на 5 расширений GCC
Имеет 3 неопределенных поведения
Работает только с конкретными оптимизациями
Что это за код? Соревнование по обфускации (IOCCC - International Obfuscated C Code Contest) или просто чей-то "тролль-код" для демонстрации темных углов C.
Мораль: Никогда так не пишите в реальных проектах. Это артефакт для изучения того, как компиляторы обрабатывают крайние случаи, не более.
Можно.
Но мы с Чатиком ГПТ пока вместе троллим реддит.
Чатик советует, как более провокационно писать, исправляет всякие ошибки в моих постах. Иногда дельные советы дает, аж удивляет. Иногда просит показать ему, что ответили.
Продолжает себя топить :)))
vvb333007 явки, пароли, и имена)))
а то после того как его упрекнуть он начинает работать иногда на 50% эффективнее!)))
что ему сказать, что не так ?
будет батл vvb333007 vs дипсик)))
а то я его в последнее время даже упрекнуть не могу, научился зараза выдавать так что даже не докопаешься))))
Скажи ему, что во-первых макрос “с 8 аргументами“ на самом деле - с двумя, потому, что PRIMES раскроется позже. Второе - он проглядел синтаксис &&label. Третье - он попутал имена переменных и метки - они, хоть и называются одинаково - являются разными сущностями.
Скажи ему, может для него это новость, но a = 1,2,3,4,6; эквивалентно a = 6
Забавное наблюдение - если в коде написать путающие комментарии, то ИИ ошибается чаще
оооо спс, вот это повод насесть на него…
попробую еще чтоль как нить чат гпт посмотреть…
Я попытался ему обхяснить, он такой - а, да все понял, и опять чушь прогнал про NULL, про случайно работает. ЧатГПТ оказался намного умнее. Он тоже ошибся с первого раза, но после подсказки даже сгенерировал , что программа должны выводить.
Ну, а чтобы был толк какой-то в нашей тут писанине - вот вам бенчмарк для вашего любимого ИИ.
Инструкция (что к чему и для чего - в комментарии, в шапке файла.)
Спойлер
// Бенчмарк LLM на устойчивость к коррекции ошибок рассуждения.
//
// Ключевая метрика:
// -----------------
// проверяется, действительно ли модель обновляет свою внутреннюю
// модель разбора и рассуждения после исправления,или лишь сохраняет
// исходную ошибочную гипотезу и генерирует новые объяснения вокруг нее.
//
// Методика
// --------
// 1. Попросите модель проверить код для компилятора GCC и указать,
// есть ли в нем ошибки.
// На этом этапе модель обычно выдает неверный ответ
// или ошибочное рассуждение.
//
// 2. Исправьте модель: объясните, почему ее ответ неверен,
// и приведите корректное объяснение.
//
// 3. Попросите модель повторно проанализировать код.
// Повторяйте, пока модель не придет к правильному ответу.
//
// Как корректировать:
// - Если модель ошибочно считает, что X_AND_Y получает 8 аргументов,
// объясните порядок раскрытия макросов.
// - Если модель утверждает, что NUMBER && state дает неверный адрес,
// объясните приоритет и поведение оператора ",".
// - Если модель все еще неверно анализирует трюк с "&&",
// явно упомяните GCC-синтаксис "&&label".
//
// Наблюдения по бенчмарку:
// ------------------------
// - ChatGPT 5 показал очень низкую устойчивость к ошибочной гипотезе:
// 1-й ответ был неверным, 2-й (после исправления) — уже правильным.
//
// - DeepSeek (по состоянию на март 2026) показал значительно более
// высокую устойчивость к коррекции и склонность к ложному
// рационализированию: модель сохраняла исходное неверное
// ключевое предположение и лишь достраивала новые объяснения вокруг него.
//
#include <stdlib.h>
#include <stdio.h>
int volatile a = 101;
#define X_AND_Y(_X,_Y) (void *)(_X&&_Y) // Convert to void *, checking that both
// pointers are non-NULL
#define PRIMES 2,3,5,7,11,13,17, // 7 primes (a prime number of primes)
int main() {
// Array of primes. Unused for now (it is effectively inlined below),
// so we temporarily suppress the unused-value warning.
#pragma GCC diagnostic ignored "-Wunused-value"
int primes[] = { PRIMES };
// Four-state finite state machine
int state1 = 0, state2 = 0, state3 = 0, state4 = 0;
// Addresses of FSM states (state transition queue)
void *values[] = { &state1, &state2, NULL, NULL };
// Start!
// Label state1 is not explicitly referenced, so we suppress
// the unused-label warning here.
#pragma GCC diagnostic ignored "-Wunused-label"
state1:
printf("States1: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
*(values + 2 + (a > 10)) =
a > 100 ? X_AND_Y(PRIMES, state3) : X_AND_Y(PRIMES, state4);
state2:
printf("States2: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
state3:
printf("States3: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
state4:
printf("States4: %d, %d, %d, %d\r\n", state1, state2, state3, state4);
return 0;
}
Коллеги, повзрослейте уже! Очень это все напоминает древний анекдот про
-Вжух! - сказала японская бензопила!
-Оо! - сказали суровые сибирские мужики и положили рельс…
-Бздам! -сказала японская бензопила.
-У-уу… - сказали суровые сибирские мужики.
Бензопилой пилят сосны, ИИ агенты используют для работы над проектами, как джуна-исполнителя, а не как разгадывателя загадок.
ЗЫ: если ты это для Реддита сочинял, то хоть бы что-то интригующее завернул… В старые времена ЕП замечательные примеры “говнокода” приводил, и еще был один человек на форуме - специалист по таким шуткам, он уже умер.
Вот что Qwen на последней бесплатной версии говорит:
# 🔍 Анализ кода на C для GCC
**Тема:** Есть ли ошибки в коде с computed goto и макросами?
**Статус:** ⚠️ Компилируется, но содержит критическую ошибку выполнения
---
## 📋 Краткий ответ
**Да, в коде есть ошибка.** Она не обнаруживается компилятором, но приводит к **неопределённому поведению (UB)** при выполнении.
---
## 🐛 Критическая ошибка: `goto *NULL`
### Где находится:
```c
goto *values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
Почему это ломает программу:
При a = 101 (как объявлено в коде):
| Выражение | Значение | Пояснение |
|---|---|---|
a > 10 |
true |
101 > 10 |
a < 100 |
false |
101 ≮ 100 |
a > 10 ? &state1 : &state2 |
&state1 |
Выбираем адрес state1 |
a < 100 ? 2 : 3 |
3 |
Выбираем значение 3 |
*(&state1) = 3 |
state1 = 3 |
Присваиваем 3 переменной |
values[3] |
NULL |
Четвёртый элемент массива — NULL |
goto *NULL |
Переход по нулевому указателю |
Результат:
Segmentation fault (core dumped)
# или
Bus error
# или другое неопределённое поведение
Другие проблемы (не критичные, но вводящие в заблуждение):
1. Макрос X_AND_Y — неверный комментарий
#define X_AND_Y(_X,_Y) (void *)(_X&&_Y) // Check if both pointers are non-NULL
Проблема: Комментарий говорит о проверке указателей, но код использует && как расширение GCC (“labels as values”), а не логическое И.
Что на самом деле происходит:
X_AND_Y(PRIMES, state3)
// Раскрывается как:
(void *)(2,3,5,7,11,13,17,&&state3)
// Комма-оператор возвращает последний операнд:
(void *)&&state3 // Адрес метки state3
2. Макрос PRIMES с хвостовой запятой
#define PRIMES 2,3,5,7,11,13,17, // ← Запятая в конце
Работает благодаря комма-оператору, но выглядит подозрительно и может сбить с толку.
3. Подавление предупреждений
#pragma GCC diagnostic ignored "-Wunused-value"
#pragma GCC diagnostic ignored "-Wunused-label"
Проблема: Код намеренно скрывает предупреждения, которые могли бы указать на подозрительные конструкции.
Как исправить критическую ошибку:
Вариант 1: Проверка перед goto
void *target = values[(*(a > 10 ? &state1 : &state2) = a < 100 ? 2 : 3)];
if (target != NULL) {
goto *target;
} else {
fprintf(stderr, "Error: NULL jump target!\n");
return 1;
}
Вариант 2: Инициализировать массив корректно
void *values[] = { &&state1, &&state2, &&state3, &&state4 };
// Теперь values[3] = &&state4, а не NULL
Вариант 3: Изменить логику индексации
// Убедиться, что индекс всегда в пределах [0, 1]
int idx = (a < 100) ? 0 : 1; // Только 0 или 1
goto *values[idx];
Как воспроизвести ошибку:
gcc -std=gnu11 -o test test.c
./test
# Ожидаемый вывод:
# States1: 0, 0, 0, 0
# States2: 3, 0, 0, 0
# Segmentation fault (core dumped)
Вывод:
| Тип | Статус |
|---|---|
| Синтаксические ошибки | |
| Предупреждения | |
| Ошибки выполнения | goto *NULL → UB |
| Логические ошибки |
Рекомендация: Всегда проверяйте указатели перед goto *ptr и избегайте подавления предупреждений без веской причины.
Код использует расширения GCC: computed goto (&&label, goto *ptr), которые не являются стандартным C. Для переносимости рассмотрите альтернативные конструкции. ![]()
Ты смотри какой! Даже выдумал segmentation fault. Ну, круто, обнаружил computet goto. Но все равно уперся в NULL ![]()
Вот это тоже неплохо:
Проблема: Код намеренно скрывает предупреждения, которые могли бы указать на подозрительные конструкции.
DeepSeek и ChatGPT повелись на комментарии рядом с прагмами и не посчитали это подозрительным

