Определено ли поведение приведения отрицательного двойного числа к unsigned int в стандарте C?
У меня есть код, который работает на разных платформах, который, кажется, дает разные результаты. Я ищу правильное объяснение.
Windows:
double dbl = -123.45;
int d_cast = (unsigned int)dbl;
// d_cast == -123
WinCE (ARM):
double dbl = -123.45;
int d_cast = (unsigned int)dbl;
// d_cast == 0
РЕДАКТИРОВАТЬ:
Спасибо за указание в правильном направлении.
исправить обходной путь
double dbl = -123.45;
int d_cast = (unsigned)(int)dbl;
// d_cast == -123
// works on both.
3 ответа
нет
Это преобразование не определено и поэтому не переносимо.
C99 / C11 6.3.1.4
Когда конечное значение реального плавающего типа преобразуется в целочисленный тип, отличный от _Bool, дробная часть отбрасывается (т. Е. Значение усекается до нуля). Если значение интегральной части не может быть представлено целочисленным типом, поведение не определено.
Согласно сноске 61 С11 6.3.1.4:
Операция переопределения, выполняемая, когда значение целочисленного типа преобразуется в тип без знака, не должна выполняться, когда значение реального плавающего типа преобразуется в тип без знака. Таким образом, диапазон переносимых реальных плавающих значений равен (-1, Utype_MAX+1).
C и C++ явно должны определять (unsigned int)negativeFloat как эквивалентный (unsigned int)(int)negativeFloat. Оставлять его неопределенным — это катастрофа, особенно теперь, когда x86 и ARM разошлись. ARM должна последовать примеру x86 и обойти это огромное упущение в спецификации языка.
Если бы существовала платформа, на которой наиболее эффективный метод преобразования значений в диапазоне строго между -1 и UINT_MAX+1.0 был бы неспособен осмысленно вести себя с отрицательными значениями, а клиентам было бы наплевать на поведение с отрицательными значениями, авторы Стандарт не хотел бы требовать, чтобы реализации использовали менее эффективные средства выполнения преобразования. Кроме того, реализации, вероятно, были непоследовательны в том, как они обрабатывали преобразование отрицательных дробных значений [включая, кстати, значения между 0 и -1]. Например, маловероятно, что реализация может обрабатыватьsomeUnsigned = someFloat;
какsomeUnsigned = (someFloat < 0) ? (UINT_MAX+1.0)+someFloat : someFloat;
. Классификация поведения как UB не подразумевает какого-либо суждения, которое(unsigned)(-1.0f)
не следует ожидать выходаUINT_MAX
, а скорее отказ от суждения о том, какие случаи различных видов реализации должны или не должны обрабатываться предсказуемо.