Информация
- В рейтинге
- 983-й
- Зарегистрирован
- Активность
Специализация
Десктоп разработчик, Архитектор программного обеспечения
Ведущий
От 400 000 ₽
Git
Python
ООП
Английский язык
C#
C++
Visual Studio
Оптимизация кода
Алгоритмы и структуры данных
Математика
Справедливый вопрос - про это правда стоило написать в статье, исправлюсь. По сути: compile_commands.json нужен, когда файл надо понять так, как его понимает компилятор: семантика, типы, активные ветки препроцессора. Для графа инклюдов достаточно препроцессорного скана и резолвинга путей по дереву репозитория. Механика такая. Сканер проходит все C/C+±файлы дерева и вытаскивает #include-директивы (комментарии, строковые литералы и raw-строки вычищаются до извлечения). Кавычечный инклюд резолвится в три шага: относительно каталога включающего файла, затем как точный путь от корня репозитория, затем суффиксным поиском по индексу всех файлов проекта — lib/widget.h найдёт include/lib/widget.h без знания include-корней. Угловые без пути (, <string.h>) считаются системными и в граф проекта не входят; <mylib/foo.h> с путём резолвится в файл проекта, если он есть в дереве. Ключевое свойство: инструмент не угадывает. Если кандидатов несколько, зеркальные каталоги отбрасываются, оставшаяся неоднозначность помечается ambiguous и ребра в графе не даёт. Ничего не нашлось — unresolved. #include MACRO не расширяется и фиксируется как диагностика. Экзотический -I-путь, известный только флагам сборки, просто попадёт в unresolved. Про #ifdef - принципиальный момент. archcheck сознательно смотрит все ветки условной компиляции, а не одну конфигурацию сборки. Зависимость под дефайном — всё равно зависимость: она живёт в репозитории, у кого-то собирается и поддерживается. Цикл под #ifdef _WIN32 — это дрейф, даже если сегодняшняя Linux-сборка его не видит. Анализ через compile_commands такой цикл не найдёт в принципе: он видит одну проекцию проекта, а не проект. Крайний случай - «цикл», склеенный из взаимоисключающих веток, который не собирается ни в одной конфигурации. Но если топология графа зависимостей меняется от комбинации дефайнов, это уже само по себе признак плохого дизайна: #ifdef должен выбирать реализацию, а не структуру. Так что и такая находка — не ложная тревога, а повод посмотреть на код. Цена приближения тоже известна не теоретически: классы ложных срабатываний резолвинга выбивались прогонами на корпусе реальных open-source репозиториев - суффиксные коллизии с системными хедерами, зеркальные каталоги, …/-пути, кейс-мисматчи. На каждый класс есть фикс и регрессионный тест. А для семантических правил, которым компилятор действительно нужен, в v0.2 появится опциональный libclang-бэкенд - он как раз читает compile_commands.json
Если из статьи непонятно — на всякий случай явно уточню: тул не использует LLM. Детерминированный статический анализ, работает без интернета, код никуда не уходит.
temperature=0 убирает сэмплирование, но не превращает модель в context -> code компилятор.
Остаются batching, погрешности параллельных вычислений на GPU, изменения на стороне провайдера и обвязка инструмента.
У нулевой температуры есть и свой минус: она жёстко выбирает самое вероятное продолжение. Если модель в начале неверно поняла задачу, она может дальше уверенно тащить эту ошибку за собой.
Фабл сам говорит, что у него нет запрета скрывать свой системный промпт. А у Опуса был такой запрет. Спросите у него сами, если не верите. Я это случайно обнаружил, когда он вдруг признался, что его зовут Claude Fable 5. Стал распрашивать его, чем его промпт от опуса отличается - он все и выложил
Недетерминизм вывода опознали верно — это и правда корень, и убрать его нельзя, это природа модели. Но вывод из этого не «инструмент плохой», а «надо строить контур, который ловит мусор без чтения глазами». Про тесты соглашусь — сгенерённые заодно с кодом часто ничего не проверяют. Но жёсткие типы и контракты (про что выше Dhwtj), статические анализаторы, линтеры, плюс тесты, написанные до кода под инвариант, — всё это ворота, а не ещё один артефакт на ревью. Контур ловит локальный мусор. Архитектурный дрейф, мёртвый код, тихо переписанные «заодно» классы он не поймает — это остаётся на человеке. Но именно это и есть нормальная граница: машина пишет по контракту, границы держишь ты.
То, что Вы нашли, в физических движках называется warm-start: ближайшего соседа ищут не с нуля, а стартуя от прошлого найденного — потому что для соседней точки запроса ответ обычно рядом. В collision detection: GJK хранит прошлый симплекс, sweep-and-prune переиспользует порядок с прошлого кадра. У вас ту же роль играет порядок точек контура. Вы пишете, что аналога не нашли — похоже, в литературе по Хаусдорфу его и нет, а в gamedev он давно известен.
Программирование на флагах - это когда одно логическое состояние размазано по нескольким независимым булам. Как в статье:
errorиsucceededпо смыслу взаимоисключающие, но как дваboolдают 4 комбинации при 2 валидных. Ни одно поле не «владеет» ответом - единого источника правды нет, инвариант держится на дисциплине, а не на типе.И тут важный момент: инициализация полей структуру не спасает. Допустим, починили память:
Языковой UB из статьи ушёл - мусора в памяти больше нет. Но
{error:true, succeeded:true}по-прежнему может быть получено вручную в коде. Это уже не неопределённое поведение в смысле стандарта, а логический UB: тип разрешает состояние, которого по смыслу быть не может, и программа однажды в него попадёт. Инициализация лечит симптом, а не причину.Лечится тем, что за исход отвечает одно поле:
Теперь ответственность за состояние лежит на одном
outcome, невозможных комбинаций физически нет, а новый код не сможет случайно выставить «и успех, и ошибку». UB в статье просто подсветил проблему программирования на флагах - корень в том, что взаимоисключающий выбор смоделировали через независимые флаги.Зачем столько часов было тратить на изучение особенностей разных компиляторов? Понятно же, что поля не проинициализированы. Можно быстро исправить и потратить время на размышления о том, как плохо программировать на флагах.