Casting an array of unsigned chars to an array of floats

18,628

Solution 1

I think the best way is to use a function object:

template <typename T> // T models Any
struct static_cast_func
{
  template <typename T1> // T1 models type statically convertible to T
  T operator()(const T1& x) const { return static_cast<T>(x); }
};

followed by:

std::transform(char_buff, char_buff + len, float_buff, static_cast_func<float>());
std::transform(float_buff, float_buff + len, char_buff, static_cast_func<unsigned char>());

This is the most readable because it says what is being done in English: transforming a sequence into a different type using static casting. And future casts can be done in one line.

Solution 2

Your solution is pretty much the best option, however, I would consider switching to:

char_buff[i]= static_cast<unsigned char>(float_buff[i]);

Solution 3

Your solution seems right, though on the way back, you might lose the floating digits in the casting.

Solution 4

For what purpose are you doing this? Shoving a float into a char doesn't really make sense. On most platforms a float will be 4 bytes and represent a floating point number, where as a char will be 1 byte and often represents a single character. You'll lose 3 bytes of data trying to shove a float into a char, right?

Solution 5

Your first loop doesn't require a cast. You can implicitly convert from one type (e.g., unsigned char) to a wider type (e.g., float). Your second loop should use static_cast:

for (i=0; i< len; i++)
    char_buff[i]= static_cast<unsigned char>(float_buff[i]);

We use static_cast to explicitly tell the compiler to do the conversion to a narrower type. If you don't use the cast, your compiler might warn you that the conversion could lose data. The presence of the cast operator means that you understand you might lose data precision and you're ok with it. This is not an appropriate place to use reinterpret_cast. With static_cast, you at least have some restrictions on what conversions you can do (e.g., it probably won't let you convert a Bird* to a Nuclear_Submarine*). reinterpret_cast has no such restrictions.

Also, here's what Bjarne Stroustrup has to say about this subject.

Share:
18,628
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    What is the best way of converting a unsigned char array to a float array in c++?

    I presently have a for loop as follows

    for (i=0 ;i< len; i++)
        float_buff[i]= (float) char_buff[i];
    

    I also need to reverse the procedure, i.e convert from unsigned char to float (float to 8bit conversion)

    for (i=0 ;i< len; i++)
        char_buff[i]= (unsigned char) float_buff[i];
    

    Any advice would be appreciated

    Thanks

  • Admin
    Admin about 15 years
    Thanks I need to convert from float to 8bit
  • Michael Burr
    Michael Burr about 15 years
    The cast will perform a conversion - truncating the fractional portion of the float away. This may be exactly what the person wants. One key thing to be aware of is that if the integral portion of the float can't be represented in an unsigned char (generally if it's not in the range 0-255) it's undefined.
  • Admin
    Admin about 15 years
    Thanks Michael, I dont mind losing the fractional part. If the float is less than 255, will the cast work OK? I was going to clamp the result to 255 if the float was greater than this. Thanks
  • Steve Jessop
    Steve Jessop about 15 years
    @miki: The cast will work if the float value is in the range of unsigned char. That's almost always 0..255, but it might very rarely be something different. As long as you clamp the float to the range 0 to UCHAR_MAX before casting, the result is defined. Otherwise you get undefined behaviour.
  • Steve Jessop
    Steve Jessop about 15 years
    Or std::copy(char_buff, char_buff+len, float_buff);
  • Gal Goldman
    Gal Goldman about 15 years
    In case the float is bigger than 255, it will have the MOD result after the cast (same as with any other overflow). For example: float = 500 -> char = 254. float = 256 -> char = 0. BTW, here's some info on static_cast: stackoverflow.com/questions/103512/…
  • Michael Burr
    Michael Burr about 15 years
    The behavior if the float is >= 256 is undefined - getting a modulo value might well be common, but it's not guaranteed.
  • Mark Ruzon
    Mark Ruzon about 15 years
    Using std::copy here exposes a flaw in STL (as well as C++). When you make a copy of something, it should be true that copy == original. By relying on implicit casting, this is no longer true, which is why implicit casting should be avoided.
  • Steve Jessop
    Steve Jessop about 15 years
    In which case: template<typename I, typename O> O convert(I start, I end, O dst) { return std::copy(start,end,dst); } ... convert(char_buf, char_buff+len, float_buff)