Конвертировать ieee 754 float в hex с помощью c - printf - PullRequest
17 голосов
/ 31 мая 2010

В идеале следующий код должен принимать число с плавающей точкой в ​​представлении IEEE 754 и преобразовывать его в шестнадцатеричное

void convert() //gets the float input from user and turns it into hexadecimal
{
    float f;
    printf("Enter float: ");
    scanf("%f", &f);
    printf("hex is %x", f);
}

Я не слишком уверен, что происходит не так. Это преобразование числа в шестнадцатеричное число, но очень неправильное.

123.1443 gives 40000000
43.3     gives 60000000
8        gives 0

так что он что-то делает, я просто не уверен, что.

Помощь будет оценена

Ответы [ 8 ]

26 голосов
/ 31 мая 2010

Когда вы передаете float в качестве аргумента переменной функции (например, printf()), она повышается до double, что в два раза больше float (по крайней мере на большинстве платформ) .

Один из способов обойти это - привести float к unsigned int при передаче его в качестве аргумента printf():

printf("hex is %x", *(unsigned int*)&f);

Это также более правильно, поскольку printf() использует спецификаторы формата для определения размера каждого аргумента.

Технически, это решение нарушает строгое правило алиасинга . Вы можете обойти это, скопировав байты float в unsigned int и затем передав его в printf():

unsigned int ui;
memcpy(&ui, &f, sizeof (ui));

printf("hex is %x", ui);

Оба эти решения основаны на предположении, что sizeof(int) == sizeof(float), что имеет место во многих 32-разрядных системах, но не обязательно.

12 голосов
/ 31 мая 2010

Если поддерживается, используйте% a для преобразования числа с плавающей запятой в стандартный шестнадцатеричный формат. Вот единственный документ Я мог найти, что перечислил% a вариант.

В противном случае вы должны вытянуть биты значения с плавающей запятой в целочисленный тип известного размера. Например, если вы знаете, что float и int 32-битные, вы можете выполнить быстрое приведение:

printf( "%08X" , *(unsigned int*)&aFloat );

Если вы хотите меньше зависеть от размера, вы можете использовать объединение:

union {
  float f;
//char c[16]; // make this large enough for any floating point value
  char c[sizeof(float)]; // Edit: changed to this
} u;

u.f = aFloat;
for ( i = 0 ; i < sizeof(float) ; ++i ) printf( "%02X" , u.c[i] & 0x00FF );

Порядок цикла будет зависеть от порядкового номера архитектуры. Этот пример с прямым порядком байтов.

В любом случае, формат с плавающей запятой может не быть переносимым на другие архитектуры. Параметр% a предназначен для.

3 голосов
/ 06 октября 2012

HEX для плавания

Я потратил довольно много времени, пытаясь выяснить, как преобразовать вход HEX из последовательного соединения, отформатированного как float IEE754, в float. Теперь я понимаю. Просто хотел поделиться, если это может помочь кому-то еще.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{

    uint16_t tab_reg[64]                    //declare input value recieved from serial connection
    union IntFloat {  int32_t i;  float f;  }; //Declare combined datatype for HEX to FLOAT conversion
    union IntFloat val;                     
    int i;
    char buff[50];                          //Declare buffer for string

    i=0;

    //tab_reg[i]=0x508C;                    //to test the code without a data stream,   
    //tab_reg[i+1]=0x4369;                  //you may uncomment these two lines.


    printf("Raw1: %X\n",tab_reg[i]);        //Print raw input values for debug
    printf("Raw2: %X\n",tab_reg[i+1]);      //Print raw input values for debug

    rs = sprintf(buff,"0X%X%X", tab_reg[i+1], tab_reg[i]);   //I need to swap the words, as the response is with the opposite endianness.
    printf("HEX: %s",buff);                 //Show the word-swapped string
    val.i = atof(buff);                     //Convert string to float :-)
    printf("\nFloat: %f\n", val.f);         //show the value in float

}

Выход:

Raw1: 508C
Raw2: 436A
HEX: 0X436A508C
Float: 234.314636
2 голосов
/ 08 ноября 2015

Тупо простой пример:

unsigned char* floatToHex(float val){
    unsigned char* hexVals = malloc(sizeof(float));
    hexVals[0] = ((unsigned char*)&val)[0];
    hexVals[1] = ((unsigned char*)&val)[1];
    hexVals[2] = ((unsigned char*)&val)[2];
    hexVals[3] = ((unsigned char*)&val)[3];
    return hexVals;
}

Довольно очевидное решение, когда я понял это. Нет необходимости маскировки битов, memcpy или других трюков.

В приведенном выше примере это было для определенной цели, и я знал, что число с плавающей запятой было 32 бит. Лучшее решение, если вы не уверены в системе:

unsigned char* floatToHex(float val){
    unsigned char* hexVals = malloc(sizeof(float));
    for(int i = 0; i < sizeof(float); i++){
        hexVals[i] = ((unsigned char*)&val)[i];
    }
    return hexVals;
}
2 голосов
/ 11 февраля 2014

Этот подход всегда работал для меня довольно хорошо:

union converter{
float f_val;
unsigned int u_val;
};

union converter a;
a.f_val = 123.1443f;
printf("my hex value %x \n", a.u_val);
1 голос
/ 23 января 2017

https://github.com/aliemresk/ConvertD2H/blob/master/main.c

Конвертировать Hex в Double Конвертировать Double в Hex

это коды работающего IEEE 754 плавающего формата.

1 голос
/ 21 июля 2010

Как насчет этого:?

int main(void){
  float f = 28834.38282;
  char *x = (char *)&f; 
  printf("%f = ", f);

  for(i=0; i<sizeof(float); i++){ 
    printf("%02X ", *x++ & 0x0000FF); 
  }

  printf("\n");
}
0 голосов
/ 15 ноября 2016

Что в итоге сработало для меня (как кажется, замысловато):

#include <stdio.h>
int main((int argc, char** argv)
{
    float flt = 1234.56789;
    FILE *fout;
    fout = fopen("outFileName.txt","w");
    fprintf(fout, "%08x\n", *((unsigned long *)&flt);
        /* or */
    printf("%08x\n", *((unsigned long *)&flt);
}
...