C и C ++ довольно уникальны в том смысле, что «официальные» стандарты C были написаны задолго до того, как язык уже использовался, и даже были описаны в опубликованных книгах. Было много ситуаций, таких как целочисленное переполнение, которые некоторые реализации обрабатывали бы документированным предсказуемым образом, но другие не могли делать это дешево. Стандарт рассматривает такие вещи, как «неопределенное поведение», явно отмечая, что реализация может (но не обязательна) обрабатывать их в документированной характеристике среды. Обратите внимание, что это допускает возможность того, что в некоторых средах может быть дорого гарантировать какое-либо согласованное поведение, и что многие программы могут не предлагать такие гарантии, несмотря на стоимость.
Рассмотрим, например, что-то вроде:
extern volatile int someFlag;
void test(int x, int y)
{
int z;
someFlag = 1;
z=x+y;
someFlag = 0;
if (f2())
f3(x,y,z);
}
Если в реализации, когда переполнение вызывает сигнал, разрешено изменить код на:
extern volatile sig_atomic_t someFlag;
void test(int x, int y)
{
someFlag = 1;
someFlag = 0;
if (f2())
f3(x,y,x+y);
}
Это позволит избежать необходимости сохранять значение x+y
впамять через вызов f2()
, и может избежать необходимости вычислять его полностью. Чистый выигрыш , если только someFlag
не повлияет на поведение сигнала переполнения целых чисел так, как полагается код. Если бы стандарт характеризовал целочисленное переполнение как «Определено реализацией», было бы неудобно для реализаций документировать поведение переполнения в соответствии с требованиями Стандарта, не отказываясь от оптимизаций, подобных описанным выше, даже если для многих целей гарантируется, что добавление будет выполнено довызов f2
добавил бы стоимость, но не какое-либо значение.
Вместо того, чтобы беспокоиться о том, следует ли разрешать или запрещать такую оптимизацию, авторы Стандарта решили охарактеризовать целочисленное переполнение как неопределенное поведение, позволяяреализации, которые документировали его поведение, чтобы продолжать делать это, но не требуют, чтобы реализации пессимистически предполагали, что любые возможные побочные эффекты могут быть наблюдаемы способами, о которых они не знают. До того, как был написан Стандарт, любое поведение, которое документировала реализация, было бы документированным поведением, и тот факт, что Стандарт характеризовал поведение как Неопределенное, не предназначался для его изменения.
С тех пор имел место ряд недостатков. отчеты, которые неправильно описывают как «несоответствующие» различные конструкции, которые соответствуют, но не строго , и это привело к ошибочному убеждению, что термин «X не определен» в Стандарте эквивалентен «Xзапрещен". Спецификации других языков гораздо более явны при различении конструкций, которые запрещены и должны быть диагностированы, тех, которые запрещены, но не всегда могут быть диагностированы, тех, чье поведение, как ожидается, будет частично, но не полностью согласованным, и тех, чье поведение будет вести себя вразные согласованные моды в разных реализациях, но авторы оригинальных стандартов C и C ++ оставляли такие вещи на усмотрение разработчиков.