Результатом неопределенного поведения являются такие ошибки, которые компилятор не обязан (а иногда и не в состоянии) обнаруживать. Даже если код компилируется, то программа с неопределенным выражением все равно ошибочна.
К сожалению, программы, характеризующиеся неопределенным поведением на некоторых компиляторах и при некоторых обстоятельствах, могут работать вполне нормально, не проявляя проблему. Но нет никаких гарантий, что та же программа, откомпилированная на другом компиляторе или даже на следующей версии данного компилятора, продолжит работать правильно. Нет даже гарантий того, что, нормально работая с одним набором данных, она будет нормально работать с другим.
Аналогично в программах нельзя полагаться на машинно-зависимое поведение. Не стоит, например, надеяться на то, что переменная типа int
имеет фиксированный, заранее известный размер. Такие программы называют
Компилятор применяет эти преобразования типов при использовании значений одного арифметического типа там, где ожидается значение другого арифметического типа. Например, при использовании значения, отличного от логического в условии, арифметическое значение преобразуется в тип bool
таким же образом, как при присвоении арифметического значения переменной типа bool
:
int i = 42;
if (i) //
i = 0;
При значении 0
условие будет ложным, а при всех остальных (отличных от нуля) — истинным.
К тому же при использовании значения типа bool
в арифметическом выражении оно всегда преобразуется в 0
или 1
. В результате применение логического значения в арифметическом выражении является неправильным.
Хотя мы сами вряд ли преднамеренно присвоим отрицательное значение объекту беззнакового типа, мы можем (причем слишком легко) написать код, который сделает это неявно. Например, если использовать значения типа unsigned
и int
в арифметическом выражении, значения типа int
обычно преобразуются в тип unsigned
. Преобразование значения типа int
в unsigned
выполняется таким же способом, как и при присвоении:
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // выводит -84
std::cout << u + i << std::endl; // при 32-битовом int,
//
Во втором выражении, прежде чем будет осуществлено сложение, значение -42
типа int
преобразуется в значение типа unsigned. Преобразование отрицательного числа в тип unsigned
происходит точно так же, как и при попытке присвоить это отрицательное значение объекту типа unsigned
. Произойдет "обращение значения" (wrap around), как было описано выше.
При вычитании значения из беззнакового объекта, независимо от того, один или оба операнда являются беззнаковыми, следует быть уверенным том, что результат не окажется отрицательным:
unsigned u1 = 42, u2 = 10;
std::cout << u1 - u2 << std::endl; //
std::cout << u2 - u1 << std::endl; //