то не написано в стандарте, и то и то собирается компилятором определённым образом.
в том, что implementation-specified behaviour имеет ограниченное поведение. например, возвращаемое значение функции system — это implementation-defined, а разыменование нулевого указателя — undefined behaviour. при попытке что-то сделать с возвращаемым значением system, программа гарантировано продолжит работать, а после разыменования нулевого указателя ничего уже не гарантируется
Не совсем понимаю. Если я напишу в с++ __int128_t, а потом соберу это на другом компиляторе - у меня нихрена не соберётся. А в случае с UB компилятор определённым образом их разрешает. Например gcc со шлангом собирают *(&arr+1)-arr как длину массива. Всегда собирают так, если значение в стеке (в куче же тоже должен, да?) то всё работает. И чем же это не дополнение компилятора?
в си нет __int128_t
В си нет, я просто не знаю какой пример из си привести. Но в плюсах есть дополнение компилятора - __int128_t. Чем подобное дополнение отличается от обрабатываемого определённым образом UB
Не определеное поведение на то и не определеное поведение что никто не знает что будет
В каком стеке? В какой куче? Стандарт вообще не оперирует такими понятиями. Ну хоть с типами языка для начала ознакомился и с классами хранения. Рассказываю для самых маленьких (ибо здесь по-моему любому это очевидно), есть 3 понятия - поведение, определяемое реализацией (сюда же можно включить и вещи, поддержка которых также определяется реализацией, будь то int64_t или vla, а также нестандартные прагмы), есть неопределённое поведение, места которого строго детерминированы стандартом, а также есть расширения компиляторов - это атрибуты, деклспецы, свои ключевые слова, да и всякие внутренние фишечки вроде определения функций внутри скоупа других функций, возвращаемое значение блоков стейтментов, автоподстановка ветки тернарника и тд. Соответственно то, что определяется реализацией, как уже сказал хиро, будет работать строго определённым образом на конкретной платформе (ну либо же не будет работать вовсе), поведение можно гарантировано узнать, прочитав документацию компилятора. Неопределённое поведение же это инварианты, предоставляемые стандартом, при нарушении которых вообще никто ничего не может гарантировать, у тебя может длина массива посчитаться, а может ракета на Вашингтон вылететь, а если рассматривать чуть более реальные варианты, то компилятору ничто не мешает твоё разыменовании адреса за границей массива преобразовать в разыменование нула - какая разница? Что так, что так поведение неопределённое. Расширения же компиляторов это то, что реализует каждый компиль самостоятельно, т.е. определённые синтаксические конструкции, которые гарантировано будут работать на конкретном компиляторе, порой даже для конкретной архитектуры (те же ассемблерные вставки). К стандарту это никакого отношения не имеет, т.к. стандарт оперирует только первыми двумя понятиями.
ID - описано в документации на компилятор и работает определённым образом . UB - не описано нигде и может работать как угодно. В частности в конкретном компиляторе конкретные ситуации неопределённого поведения могут быть описаны как какое-то вполне определенное поведение в каких-то частных случаях например в отладочной библиотеке runtime языка Освобождение неверного указателя на динамическую память например через функцию Free может вызывать какую-то вполне определённую диагностику и например завершение программы
Ты не парь себе мозги этим сейчас, по программируешь-постепенно всё поймёшь про неопределённое поведение про специфику реализации это всё не страшно просто это термины стандарта языка и это высший пилотаж технической и инженерной мысли без высшего образования и опыта в инженерии это понять сложно сразу же . Но поработав и обретение некоторую практику ты легко с этим свыкнешься и каких-то вопросов У тебя это вызывать не будет.
Самый маленький понял, спасибо.
Обсуждают сегодня