views:

1503

answers:

8

Hi.

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

+2  A: 

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

Gal Goldman
ThanksI am confused as to which c++ style cast to use (reinterpret or static) , so I just used the old style, Any ideas.Also, what happens when converting from float to unsigned char if the float is greater than 255.0. (not worried about the digits after the point)Thanks
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: http://stackoverflow.com/questions/103512/in-c-why-use-staticcastintx-instead-of-intx
Gal Goldman
The behavior if the float is >= 256 is undefined - getting a modulo value might well be common, but it's not guaranteed.
Michael Burr
+2  A: 

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?

JerSchneid
ThanksI need to convert from float to 8bit
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.
Michael Burr
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
@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
+7  A: 

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

char_buff[i]= static_cast<unsigned char>(float_buff[i]);
Reed Copsey
A: 

If you are dealing with very large arrays and performance is essential then the following may prove slightly more efficient:

   float *dst = float_buff;
   unsigned char *src = char_buff;

   for (i=0; i<len; i++) *dst++ = (float)*src++;
Dan
Thanks Dan, appreciate the tip
Or std::copy(char_buff, char_buff+len, float_buff);
Steve Jessop
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.
Mark Ruzon
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)
Steve Jessop
+1  A: 

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.

Kristo
+7  A: 

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.

Mark Ruzon
+1  A: 

The cast is automatic so you don't need to make it explicit.
But you can use the standard algorithms:

std::copy(char_buff,char_buff+len,float_buff);

Converting back from float to char there is a potential loss of information. So you need to be more explicit.

std::transform(float_buff,float_buff+len,char_buff,MyTransform());

Here we use the class MyTransform which should have an operator() that takes a float and returns a char. That should be trivial to impliment.

Martin York
A: 

No one has mentioned this, but if you're doing any arithmetic with the floats, you may want to round instead of truncate... if you have the char 49, and it gets turned into 4.9E1, after some arithmetic, it might turn into 4.89999999E1 which will turn into 48 when you turn it back into a char.

If you're not doing anything with the float, this shouldn't be a problem, but then why do you need it as a float in the first place?

Brian Postow