Рассмотрим код
void test(int mode)
{
int32_t a = 0x12345678;
int32_t b = mode ? a*0x10000 : a*0x10000LL;
return b;
}
Если этот метод вызывается с нулевым значением mode
, код вычислит длинное длинное значение 0x0000123456780000 и сохранит его в a
. Поведение этого полностью определяется стандартом C: если бит 31 результата чист, он отрезает все, кроме нижних 32 бит, и сохраняет результирующее (положительное) целое число в a
. Если бы бит 31 был установлен и результат сохранялся бы в 32-битном int
, а не в переменной типа int32_t
, реализация имела бы некоторую свободу действий, но реализациям разрешено определять int32_t
только в том случае, если они будут выполнять такие сужающие преобразования в соответствии с правила математики с дополнением до двух.
Если бы этот метод был вызван с ненулевым значением mode
, тогда числовое вычисление дало бы результат вне диапазона значения временного выражения, и как таковое вызвало бы Неопределенное поведение. Хотя правила предписывают, что должно произойти, если вычисление, выполненное для более длинного типа, сохраняется в более коротком, они не указывают, что должно произойти, если вычисления не соответствуют типу, с которым они выполняются. Довольно неприятный пробел в стандарте (который, ИМХО, должен быть закрыт) возникает с:
uint16_t multiply(uint16_t x, uint16_t y)
{
return x*y;
}
Для всех комбинаций значений x
и y
, где Стандарт говорит что-либо о том, что должна делать эта функция, Стандарт требует, чтобы она вычисляла и возвращала мод продукта 65536. Если бы Стандарт предписывал это для всех комбинаций значений x
и y
0- 65535 этот метод должен возвращать арифметическое значение (x*y) mod 65536, это было бы обязательным поведением, которому уже соответствуют 99,99% компиляторов, соответствующих стандартам. К сожалению, на машинах, где int
составляет 32 бита, Стандарт в настоящее время не налагает требований в отношении поведения этой функции в случаях, когда арифметическое произведение будет больше 2 147 483 647. Даже если любая часть промежуточного результата за пределами младших 16 бит будет игнорироваться, код попытается оценить результат, используя 32-битный целочисленный тип со знаком; Стандарт не налагает требований на то, что должно произойти, если компилятор распознает, что продукт переполнит этот тип.
person
supercat
schedule
07.05.2015
Secure
руководстве по кодированию, неверно. Возможно, я ошибочно интерпретирую стандарт C. - person Arjun Sreedharan   schedule 19.04.2014