Я пытаюсь извлечь биты из числа с плавающей точкой, не вызывая неопределенного поведения.Вот моя первая попытка:
unsigned foo(float x)
{
unsigned* u = (unsigned*)&x;
return *u;
}
Насколько я понимаю, это не гарантированно работает из-за строгих правил наложения имен, верно?Работает ли это, если предпринять промежуточный шаг с символьным указателем?
unsigned bar(float x)
{
char* c = (char*)&x;
unsigned* u = (unsigned*)c;
return *u;
}
Или я должен сам извлекать отдельные байты?
unsigned baz(float x)
{
unsigned char* c = (unsigned char*)&x;
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
Конечно, это имеет недостаток:в зависимости от порядка байтов, но я мог бы с этим смириться.
Хак с союзом - это определенно неопределенное поведение, верно?
unsigned uni(float x)
{
union { float f; unsigned u; };
f = x;
return u;
}
Просто для полноты, вот справочная версия foo
.Также неопределенное поведение, верно?
unsigned ref(float x)
{
return (unsigned&)x;
}
Итак, возможно ли извлечь биты из числа с плавающей запятой ( при условии, что оба имеют ширину 32 бита , конечно)?
РЕДАКТИРОВАТЬ: И вот версия memcpy
, предложенная Гозом.Поскольку многие компиляторы пока не поддерживают static_assert
, я заменил static_assert
на метапрограммирование некоторых шаблонов:
template <bool, typename T>
struct requirement;
template <typename T>
struct requirement<true, T>
{
typedef T type;
};
unsigned bits(float x)
{
requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
memcpy(&u, &x, sizeof u);
return u;
}