2015-01-21 2 views
0

Есть ли способ инициализировать переменную типа float с шестнадцатеричным числом? то, что я хочу сделать, это сказать, что у меня есть одноточное представление для 4, которое равно 0x40800000 в шестнадцатеричном формате. Я хочу сделать что-то вроде float a = 0x40800000, и в этом случае он принимает шестнадцатеричное значение как целое. Что я могу сделать, чтобы он рассматривался как число с плавающей запятой?Обработка шестнадцатеричного значения как значения одиночной точности или двойной точности

+1

'плыви = 4' ... –

+0

@KarolyHorvath номер i get будет в шестнадцатеричном формате, представленном в формате с плавающей запятой с одиночной/двойной точностью. – Gautam

+0

Поместите целое число вместе с поплавком в объединение. –

ответ

2

Один из вариантов заключается в использовании type punning через a union. Это defined behaviour in C since C99 (ранее это была реализация определена).

union { 
    float f; 
    uint32_t u; 
} un; 
un.u = 0x40800000; 
float a = un.f; 

Как помечено это C++, вы можете также использовать reinterpret_cast.

uint32_t u = 0x40800000; 
float a = *reinterpret_cast<float*>(&u); 

Перед выполнением любой из них, вы должны подтвердить, что они того же размера:

assert(sizeof(float) == sizeof(uint32_t)); 
+1

Как вы используете 'reinterpret_cast' здесь? – TonyK

+0

@TonyK Он говорит, что не используйте C-style casts в ссылке, используйте 'reinterpret_cast'. –

+0

@JonathanMee: Может быть, он говорит это (например, 'f = * reinterpret_cast (& i)'). Но тогда вам вообще не нужны союзы. И почему «тоже»? – TonyK

1

Вы можете сделать это, если ввести переменную временного целого типа, приведение его в плавающее точечный тип и разыгрывать его. Вы должны быть осторожны с размерами задействованных типов и знать, что они могут измениться. С моим компилятором, например, это работает:

unsigned i = 0x40800000; 
float a = *(float*)&i; 
printf("%f\n", a); 
// output 4.00000 
+0

Хотя это может сработать, я уверен, что это неопределенное поведение по спецификации, поэтому остерегайтесь драконов и всего этого. –

+0

@SimonByrne Это идентично использованию 'union' при условии, что' sizeof (unsigned) == sizeof (float) ', поэтому, возможно, там должен быть' assert'. –

+3

@JonathanMee Нет, одно не определено поведение на C, а другое - нет. Это означает, что компилятор может и будет оптимизировать, полагая, что '* (float *) & i' не происходит. Компиляторы C и C++ перестали быть по очереди переводчиками из источника в сборку около пятнадцати лет назад (http://www.drdobbs.com/cpp/type-based-alias-analysis/184404273) –

1

Я не знаю, как вы получаете ваше значение «0x40800000».

Если это подходит в качестве int вы можете просто сделать:

const auto foo = 0x40800000; 
auto a = *(float*)&foo; 

Если это приходит в виде строки, вы можете сделать:

float a; 

sscanf("0x40800000", "0x%x", &a); 
+0

0x40800000 - это то, что двоичное представление в памяти 4 выглядит как в формате IEEE 754. См. [This] (http://www.h-schmidt.net/FloatConverter/IEEE754.html) для интерактивного примера. Если, например, вы писали низкоуровневый, ориентированный на архитектуру, оптимизированный по циклу десериализатор для 32-разрядного IEEE754, тогда вы могли бы сделать то, что вы предлагаете в своем первом примере. –

+0

@AndyBrown My, наряду со всеми другими текущими ответами, просто предположим, что 'int' имеет тот же размер, что и' float', * и *, что 'float', представленный« 0x40800000 », имеет тот же формат, который используется текущая архитектура. Пока оба они верны, нет необходимости писать десериализатор. Достаточно простого «союза» или литья. –

Смежные вопросы