Получение битов одинарной точности IEEE для числа с плавающей запятой

Мне нужно записать число с плавающей запятой одинарной точности IEEE в 32-битный аппаратный регистр по определенному адресу. Для этого мне нужно преобразовать переменную типа float в целое число без знака. Я могу получить целочисленное представление следующим образом:

float a = 2.39;
unsigned int *target;
printf("a = %f\n",a);
target = &a;
printf("target = %08X\n",*target);

который возвращает:

a = 2.390000
target = 4018F5C3

Все хорошо. Однако это вызывает предупреждение компилятора «cast.c: 12: предупреждение: назначение из несовместимого типа указателя»

Есть ли другой способ сделать это, который не генерирует предупреждение? Это для конкретного оборудования, мне не нужно обрабатывать разные порядки байтов и т. Д., И я не хочу перебирать каждый символ по соображениям производительности, как предполагают некоторые другие вопросы. Кажется, вы могли бы использовать reinterpret_cast в C++, но я использую C.


person mc_electron    schedule 24.07.2012    source источник


Ответы (4)


Вы можете использовать каламбур с союзом,

union {
    float f;
    uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;

чтобы получить биты. Или вы можете использовать memcpy.

person Daniel Fischer    schedule 24.07.2012

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

union reg_val
{
  float f_val;
  unsigned int i_val;
} myRegister;
myRegister.f_val = 2.39;
printf("target = %08X", myRegister.i_val);
person hair raisin    schedule 24.07.2012

Если вы пытаетесь просто отобразить интегральное значение float в том виде, в каком оно хранится в памяти, попробуйте использовать объединение:

union {
    float a;
    unsigned int target;
} u;

Сохраните значение с плавающей запятой:

u.a = 2.39;

Распечатайте как значения с плавающей запятой, так и целые числа:

printf ("a = %f\n", u.a);
printf ("target = %08X\n", u.target); /* you could use %u to show decimal */

Нет предупреждений компилятора. Я использую компилятор GNU (gcc) в Linux. Обратите внимание, что target не указатель; в этом красота (и безобразие) союзов. ;-)

person pr1268    schedule 24.07.2012
comment
Черт... Дэниел Ф. и изюм для волос опередили меня. Думаю, я должен печатать быстрее! - person pr1268; 25.07.2012

РЕДАКТИРОВАТЬ: решение union работает везде, где я его пробовал, но где-то на SO мне указали на стандарты, которые показали, что оно не должно работать. См. ссылку ниже в комментариях, чтобы найти НАМНОГО больше информации об этом (Спасибо, Дэниел!). Предполагается, что он работает или не должен работать, я бы использовал его с осторожностью, я думаю, что порядок следования байтов и т. Д. Также задействован (двойные разбивки на байты и т. Д.).

Другое решение — фиктивная asm-функция. Например на руке:

.globl echo 
echo:
   bx lr


unsigned int echo ( float );
...
unsigned int ra; float f;
f=1.0;
ra=echo(f);

требуется некоторая разборка, она должна быть в системе, которая не имеет fpu и/или использует gprs для переноски поплавков.

memcpy, как уже упоминалось, является самым чистым, надежным и переносимым решением (помните о порядке следования байтов).

person old_timer    schedule 24.07.2012
comment
Если он не был изменен с момента последнего черновика, сноска 95 в 6.5.2.3 гласит, что если элемент, используемый для чтения содержимого объекта объединения, не совпадает с элементом, который последний раз использовался для хранения значения в объекте, соответствующая часть объектное представление значения переинтерпретируется как объектное представление в новом типе, как описано в 6.2.6 (процесс, иногда называемый «каламбуром типа»). Это может быть представление-ловушка, так что официально это должно работать. (Хорошо, сноски носят только информативный характер, поэтому они явно необходимы для работы). - person Daniel Fischer; 25.07.2012
comment
@DanielFischer: В черновике n1124, похоже, нет этой сноски (или я ее пропустил). Раздел 6.2.6.1.7, кажется, сокращает это: когда значение хранится в члене объекта типа union, байты представления объекта, которые не соответствуют этому члену, но соответствуют другим членам, принимают неуказанные значения. Предупреждение повторяется в Приложении J.1, в котором утверждается, что не указано следующее: Значение члена объединения, отличного от последнего сохраненного в (6.2.6.1) - person sfstewman; 25.07.2012
comment
А, я говорил о n1570 (C11). Извините, что не упомянул об этом. - person Daniel Fischer; 25.07.2012
comment
@DanielFischer: я нахожу это достаточно запутанным, чтобы задать его как вопрос: stackoverflow.com/questions/11639947/. Может быть, вы сможете пролить свет? - person sfstewman; 25.07.2012