12oni
12oni

Reputation: 85

How to convert a float to a 4 byte char in C?

I want to convert a float number for example 2.45 to the 4 byte char array. so the 2.45 should look like this '@' 'FS' 'Ì' 'Í' which is binary the ieee representation of 2.45 = 01000000 00011100 11001100 11001101?

I've solved the problem but it has a bad complexity. do you have any good ideas?

Thanks for the good answers.

can you please tell me the way back from the char array to the float number ?

Upvotes: 7

Views: 43076

Answers (3)

Miguel Tomás
Miguel Tomás

Reputation: 1911

one can convert a float to a char using typecasting and pointers as follows:

float t= -2.63646464;
char *float2CharArr;
float2CharArr = (char*) &t;

Mind you above there's no \0 string terminator. To append it one can do it, for instance, like so:

char* tmp = realloc(float2CharArr, sizeof(*float2CharArr)+1);
tmp[sizeof(*float2CharArr)+1] = '\0';
float2CharArr=tmp;

Another, more elaborate way to convert a float value into a char string can be achieved using the following code below:

union int32_Float_t 
{
  int32_t Long;
  float Float;
};
 
#ifndef HUGE_VALF
#define HUGE_VALF (__builtin_huge_valf())
#endif
 
#ifndef FLT_MIN_EXP
#define FLT_MIN_EXP (-999)
#endif
 
#ifndef FLT_MAX_EXP
#define FLT_MAX_EXP (999)
#endif
 
#define _FTOA_TOO_LARGE -2  // |input| > 2147483520 
#define _FTOA_TOO_SMALL -1  // |input| < 0.0000001 
 
//precision 0-9
#define PRECISION 7
 
//_ftoa function 
void _ftoa(float f, char *p, int *status) 
{
  int32_t mantissa, int_part, frac_part;
  int16_t exp2;
  int32_Float_t x;
 
  *status = 0;
  if (f == 0.0) 
  {
    *p++ = '0';
    *p++ = '.';
    *p++ = '0';
    *p = 0;
    return;
  }
 
  x.Float = f;
  exp2 = (unsigned char)(x.Long>>23) - 127;
  mantissa = (x.Long&0xFFFFFF) | 0x800000;
  frac_part = 0;
  int_part = 0;
 
  if (exp2 >= 31) 
  {
    *status = _FTOA_TOO_LARGE;
    return;
  } 
  else if (exp2 < -23) 
  {
    *status = _FTOA_TOO_SMALL;
    return;
  } 
  else if (exp2 >= 23)
  { 
    int_part = mantissa<<(exp2 - 23);
  }
  else if (exp2 >= 0) 
  {
    int_part = mantissa>>(23 - exp2);
    frac_part = (mantissa<<(exp2 + 1))&0xFFFFFF;
  } 
  else 
  {
    //if (exp2 < 0)
    frac_part = (mantissa&0xFFFFFF)>>-(exp2 + 1);
  }
 
  if (x.Long < 0)
      *p++ = '-';
  if (int_part == 0)
    *p++ = '0';
  else 
  {
    ltoa(int_part, p, 10);
    while (*p)
      p++;
  }
  *p++ = '.';
  if (frac_part == 0)
    *p++ = '0';
  else 
  {
    char m;
 
    for (m=0; m<PRECISION; m++) 
    {
      //frac_part *= 10;
      frac_part = (frac_part<<3) + (frac_part<<1); 
      *p++ = (frac_part>>24) + '0';
      frac_part &= 0xFFFFFF;
    }
 
    //delete ending zeroes
    for (--p; p[0] == '0' && p[-1] != '.'; --p)
      ;
    ++p;
  }
  *p = 0;
}
 

Below is an example on how to using on Arduino Studio and related coding platforms for MCU programming:

void setup(void) 
{
  int i, stat;
  char s[20];
  float f[] = { 0.0, -0.0, 42.0, 123.456789, 0.0000018, 555555.555, 
                   -888888888.8888888, 11111111.2 };
                    
  Serial.begin(9600);
 
  for ( i=0; i<8; i++ ) 
  {
    if ( _ftoa(f[i], s, &stat) == 0 ) 
    {
      Serial.print( "_ftoa: " ); 
      Serial.println( s );
    }
  }
}
 
void loop(void) { }

This source code is posted around the internet in various places, mostly without attribution. For instance here and here. So credit to the anonymous author.

Upvotes: 0

Paul R
Paul R

Reputation: 212969

Just use memcpy:

#include <string.h>

float f = 2.45f;
char a[sizeof(float)];

memcpy(a, &f, sizeof(float));

If you require the opposite endianness then it is a trivial matter to reverse the bytes in a afterwards, e.g.

int i, j;

for (i = 0, j = sizeof(float) - 1; i < j; ++i, --j)
{
    char temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

Upvotes: 13

Some programmer dude
Some programmer dude

Reputation: 409176

You have a few ways of doing this, including these two:

  1. Use typecasting and pointers:

    float f = 2.45;
    char *s = (char *) &f;
    

    Note that this isn't safe in any way and that there is no string terminator after the "string".

  2. Use a union:

    union u
    {
        float f;
        char s[sizeof float];
    };
    
    union u foo;
    foo.f = 2.45;
    

    The char array can now be accessed to get the byte values. Also note like the first alternative there is no string terminator.

Upvotes: 10

Related Questions