В тех случаях, когда полезные оптимизации могут привести к тому, что некоторые аспекты выполнения программы будут вести себя не в соответствии со Стандартом (например, два последовательных чтения одного и того же байта, дающие противоречивые результаты), Стандарт обычно пытается охарактеризовать ситуации, в которых такие эффекты могут наблюдать, а затем классифицировать такие ситуации, как вызов неопределенного поведения. Он не прилагает особых усилий, чтобы гарантировать, что его характеристики не «заманивают в ловушку» некоторые действия, поведение которых, очевидно, должно обрабатываться предсказуемо, поскольку он ожидает, что создатели компилятора будут избегать глупого поведения в таких случаях.
К сожалению, есть некоторые крайние случаи, когда этот подход действительно не работает. Например, рассмотрим:
struct c8 { uint32_t u; unsigned char arr[4]; };
union uc { uint32_t u; struct c8 dat; } uuc1,uuc2;
void wowzo(void)
{
union uc u;
u.u = 123;
uuc1 = u;
uuc2 = u;
}
Я думаю, что ясно, что Стандарт не требует, чтобы байты в uuc1.dat.arr
или uuc2.dat.arr
содержали какое-либо конкретное значение, и что компилятору было бы разрешено, для каждого из четырех байтов i == 0 .. 3, скопируйте uuc1.dat.arr[i]
в uuc2.dat.arr[i]
, скопируйте uuc2.dat.arr[i]
в uuc1.dat.arr[i]
или запишите оба uuc1.dat.arr[i]
и uuc2.dat.arr[i]
с соответствующими значениями. Я не думаю, что ясно, намерен ли Стандарт требовать, чтобы компилятор выбрал один из этих вариантов действий, вместо того, чтобы просто оставить эти байты, содержащие то, что они содержат.
Очевидно, что код должен иметь полностью определенное поведение, если ничто не наблюдает за содержимым uuc1.dat.arr
или uuc2.dat.arr
, и нет ничего, что предполагало бы, что проверка этих массивов должна вызывать UB. Кроме того, не существует определенного средства, с помощью которого значение u.dat.arr
могло бы меняться между присвоениями uuc1
и uuc2
. Это предполагает, что uuc1.dat.arr
и uuc2.dat.arr
должны содержать совпадающие значения. С другой стороны, для некоторых видов программ сохранение явно бессмысленных данных в uuc1.dat.arr
и / или uuc1.dat.arr
редко будет служить какой-либо полезной цели. Я не думаю, что авторы Стандарта специально намеревались требовать таких хранилищ, но утверждение, что байты принимают значения «Unspecified», делает их необходимыми. Я ожидаю, что такая гарантия поведения будет устарела, но я не знаю, что может заменить ее.