Во многом потому, что для достижения определенных целей это необходимо. Например, C и C ++ изначально использовались для написания операционных систем, включая такие вещи, как драйверы устройств. Для этого они использовали (среди прочего) прямой доступ к конкретным аппаратным расположениям, которые представляли устройства ввода-вывода. Предотвращение доступа к этим расположениям не позволило бы использовать C по прямому назначению (а C ++ был специально нацелен на предоставление всех тех же возможностей, что и C).
Другим фактором является действительно базовое решение между указанием языка и указанием платформы . Чтобы использовать одни и те же примеры, C и C ++ основаны на сознательном решении ограничить определение языком и оставить платформу, окружающую этот язык, отдельной. В нескольких альтернативах, с использованием Java и .NET в качестве пары наиболее очевидных примеров, вместо этого указываются целые платформы.
Оба они отражают основные различия в отношении к дизайну. Одной из основных заповедей дизайна C (в основном сохраненной в C ++) было «довериться программисту». Хотя об этом никогда не говорилось так прямо, базовая концепция «песочницы» Java была / основана на идее, что вы должны не доверять программисту.
Что касается того, какие языки имеют / не имеют неопределенного поведения, это маленький грязный секрет: для всех практических целей все из них имеют неопределенное поведение. Некоторые языки (опять же, C и C ++ являются яркими примерами) прилагают значительные усилия, чтобы указать, какое поведение не определено, в то время как многие другие либо пытаются утверждать, что его не существует (например, Java), либо по большей части игнорируют многие из «темных углов» "где это возникает (например, Паскаль, большинство .NET).
Те, кто утверждает, что его не существует, обычно создают самые большие проблемы. Java, например, включает в себя довольно много правил, которые пытаются , чтобы гарантировать согласованные результаты с плавающей запятой. В процессе они делают невозможным эффективное выполнение Java на небольшом количестве оборудования, но результаты с плавающей запятой все еще не гарантируют согласованности. Хуже того, модель с плавающей запятой, которую они запрашивают, не совсем идеальна, поэтому при некоторых обстоятельствах она препятствует получению наилучших результатов, которые вы могли бы (или, по крайней мере, заставляет вас проделать большую дополнительную работу, чтобы обойти то, что она требует) .
К чести Sun / Oracle (наконец) начал замечать проблему и сейчас работает над значительно другой моделью с плавающей запятой, которая должна стать улучшением. Я не уверен, было ли это включено в Java, но я подозреваю, что когда / если это произойдет, между кодом для старой модели и кодом для новой модели будет существенный «разрыв».