C Неопределенное поведение — депрессия и ужас (обновлено)


Даже если вы достаточно опытный пользователь C, вы можете не знать о неопределенном поведении, а если вы знаете, то можете не осознавать, в какую проблему это превратилось. Новая критика предполагает, что это настолько плохо, насколько вы могли ожидать, если знать, что это такое и какую пользу от этого можно использовать.

Я интенсивно использую C, и я использую его в течение длительного времени, в основном для задач низкого уровня, которые близки к металлу. Я не являюсь академическим пользователем C в том смысле, что не трачу много времени на размышления о теории языка или о том, как его можно улучшить. Я рассматриваю это как ассемблер низкого уровня, который позволяет мне писать программы, близкие к металлу, без соприкосновения с металлом — если вы понимаете, что я имею в виду.
Несколько лет назад я начал слышать о «неопределенном поведении» и сначала отклонил это как академическую чепуху; интересная академическая чушь, но мне не о чем беспокоиться. Я был неправ.
Некоторое время я пытался придумать, как объяснить неопределенное поведение и его последствия, но проблема в том, что это постоянная проблема, а не новость, потому что что-то только что произошло.
Поэтому, когда я прочитал отличный пост в блоге Виктора Йодайкена, C Standard Undefined Behavior Versus Wittgenstein, я решил, что пришло время сделать что-нибудь, чтобы помочь.
Неопределенное поведение используется для обозначения синтаксически правильного кода C как выходящего за рамки стандарта. Поначалу это кажется разумной идеей, и она может только помочь прояснить, что входит в стандарт, а что нет. Проблема в том, что неопределенное поведение, похоже, скрывает то, чего не должно. Что еще хуже, он разрешил разработчикам компиляторов делать с ними практически все, что угодно, даже до такой степени, что они меняли значение частей программы вдали от неопределенного поведения.
Например, подписанное переполнение не определено. Однако в любой реальной машине это очень четко определено. Любая оптимизация компилятора, удаляющая тест, основанный на подписанном переполнении, нарушит работу программы, выполняющейся на реальной машине с определенным поведением. Чтобы было ясно, если я напишу цикл, который проверяет значение, которое может возникнуть только при подписанном переполнении, тогда тест на переполнение и код, который будет выполняться, могут быть удалены в интересах оптимизации.
Это не оптимизация, это вандализм.
Конечно, задолго до того, как неопределенное поведение стало обычным явлением, программистам низкого уровня приходилось бороться с оптимизатором компилятора; например, необходимость пометить переменную как изменчивую, чтобы остановить оптимизацию циклов «занято-ожидание», то есть пустых циклов.
По словам Денниса Ричи, неопределенное поведение:
лицензия для компилятора на выполнение агрессивных оптимизаций, которые полностью законны по правилам комитета, но делают хэш явно безопасных программ
Что еще хуже, люди, отвечающие за стандарты, кажутся глухими к жалобам из источников, которые, как вы могли подумать, им следует принять во внимание. Возьмите комментарий Линуса Торвальдса:
Да, давайте просто скажем, что оригинальные разработчики C лучше справлялись со своей работой, чем группа людей, занимающихся стандартами, которые создавали плохую чушь, чтобы заставить некоторые программы в стиле Fortran работать быстрее. Они также не ускоряют нормальный код, они просто вводят неопределенное поведение в большой объем кода. И удаление NULL-указателя проверяет, потому что кто-то допустил ошибку, а затем превращает эту небольшую ошибку в реальную дыру в безопасности, которую можно использовать? Не такой уж и умный.
Нам нужно беспокоиться не только о стандартах. Авторы компилятора, похоже, тоже сошли с рельсов. Когда-то целью разработчика компилятора было как можно точнее перевести код более высокого уровня в код низкого уровня. Сейчас мы, кажется, вступили в эпоху, когда написание компилятора рассматривается как выход на вершину таблицы лидеров в игре по оптимизации. Не волнуйтесь, если ваш компилятор разрушит программу с неопределенным поведением, просто посмотрите, насколько она быстрее. Цитата Виктора Йодайкена
«Под давлением, особенно со стороны Linux, компилятор GCC ввел ряд флагов для отключения поведения UB — по сути, разветвляя язык».
Какое решение проблемы?
Если предположить, что люди прислушиваются к стандартам, то одним из возможных решений является изменение неопределенного поведения на поведение, определяемое машиной. В конце концов, подписанное переполнение не может быть определено абстрактно, но обычно оно есть в конкретном случае. Написание программы C, которая работает на любом оборудовании, на самом деле не является названием игры, хотя вы можете приблизиться к этому, даже если вам нужно включить зависимости между машинами.
Иногда неопределенное поведение в шутку называют назальными демонами из-за публикации на comp.std.c о том, что, когда компилятор обнаруживает неопределенное поведение, он может делать все, что угодно, в том числе «заставить демонов летать нам из вашего носа».
Это глупо сверх разумного.
Поскольку использование неинициализированной автоматической переменной является неопределенным поведением, тогда:
int я; ANS = 2 + я;
может быть скомпилирован для «форматирования жесткого диска».
Авторы компиляторов — никаких гнусных демонов!

Обновлять:
Вскоре после того, как это было написано, Линус совершил новый удар по людям стандартов C. Возможно, нам стоит беспокоиться не только о неопределенном поведении.
«… Итак, я хочу видеть реальные реальные аргументы, а не« стандарт неясен ». Когда задокументированное поведение gcc говорит одно, а стандарт может быть неясным, нас действительно нисколько не волнует отсутствие ясности в какой-то стандарт.
Так в чем же реальная причина избегать сглаживания объединений?
В органах по стандартизации есть компетентные люди. Но они не всегда компетентны, и перевод намерения на английский также не всегда идеален. Так что стандарты — это не какая-то священная книга, которую нужно уважать.
Стандарты тоже должны быть подвергнуты сомнению «.
прочитайте остальную часть взрыва.


Добавить комментарий