Определено ли поведение приведения отрицательного двойного числа к 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, а скорее отказ от суждения о том, какие случаи различных видов реализации должны или не должны обрабатываться предсказуемо.

Другие вопросы по тегам