将无符号字符数组转换为浮点数数组

8
什么是将无符号字符数组转换为浮点数组的最佳方法?
我目前有一个for循环如下所示:
for (i=0 ;i< len; i++)
    float_buff[i]= (float) char_buff[i];

我还需要逆转过程,即将无符号字符转换为浮点数(将浮点数转换为8位)
for (i=0 ;i< len; i++)
    char_buff[i]= (unsigned char) float_buff[i];

任何建议都将不胜感激

谢谢


1
你在做什么需要这个? - graham.reeds
8个回答

11
我认为最好的方法是使用函数对象:
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); }
};

接着是:

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>());

这是最易读的,因为它用英语表述了正在进行的操作:使用静态转换将序列转换为不同类型。未来的转换可以在一行中完成。


8

您的解决方案基本上是最佳选项,但是我建议考虑切换到:

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

3
该转换是自动的,因此您无需明确指定。
但是您可以使用标准算法:
std::copy(char_buff,char_buff+len,float_buff);

将浮点数转换回字符时,可能会丢失信息。因此,您需要更加明确。

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

在这里,我们使用名为MyTransform的类,该类应该具有一个operator(),该操作符接受一个float参数并返回一个char。这应该很容易实现。


2

你的第一个循环不需要进行强制类型转换。你可以将一种类型(如unsigned char)隐式转换为更宽的类型(例如float)。你的第二个循环应该使用static_cast

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

我们使用 static_cast 来明确告诉编译器将类型转换为较窄的类型。如果您不使用转换,您的编译器可能会警告您该转换可能会丢失数据。强制转换运算符的存在意味着您知道可能会丢失数据精度,并且您对此感到满意。这 不是 使用 reinterpret_cast 的适当场所。使用 static_cast,您至少对可以进行哪些转换有一些限制(例如,它可能不允许您将 Bird* 转换为 Nuclear_Submarine*)。reinterpret_cast 没有这样的限制。
此外,这是关于此主题的 Bjarne Stroustrup 的观点。

2

您的解决方案看起来是正确的,但在返回时,您可能会失去强制转换中的浮点数位。


我对使用哪种c++类型转换(reinterpret或static)感到困惑,所以我只是使用了旧的样式。你有什么想法吗?另外,如果float大于255.0,在将其转换为unsigned char时会发生什么。(不担心小数点后的数字)谢谢 - miki
如果浮点数大于255,则在强制转换后将具有MOD结果(与任何其他溢出一样)。例如:float = 500-> char = 254。 float = 256-> char = 0。顺便说一下,这里有关于static_cast的一些信息:https://dev59.com/n3VD5IYBdhLWcg3wDXJ3 - Gal Goldman
当浮点数值 >= 256时,其行为是未定义的 - 取模可能很常见,但并不保证。 - Michael Burr

2

你这么做的目的是什么?把一个浮点数塞到字符里面其实没有什么意义。在大多数平台上,浮点数将占据4个字节并表示浮点数,而字符将占据1个字节,并且通常表示单个字符。尝试把浮点数塞到字符里面将会丢失3个字节的数据,对吗?


我需要将浮点数转换为8位。 - miki
转换将执行截断浮点数的小数部分。这可能正是该人想要的。需要注意的一件重要事情是,如果浮点数的整数部分无法表示为无符号字符(通常如果它不在0-255范围内),则未定义。 - Michael Burr
谢谢Michael,我不介意失去小数部分。如果浮点数小于255,强制转换是否可以正常工作?如果浮点数大于255,我打算将结果夹紧到255。 谢谢 - miki
2
@miki:如果浮点值在无符号字符范围内,强制转换就会起作用。这几乎总是0..255,但很少可能是其他值。只要在强制转换之前将浮点数夹紧到0到UCHAR_MAX的范围内,结果就是定义好的。否则,您将得到未定义的行为。 - Steve Jessop

0

如果你正在处理非常大的数组,而且性能至关重要,那么以下方法可能会稍微更有效:

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

   for (i=0; i<len; i++) *dst++ = (float)*src++;

或者 std::copy(char_buff, char_buff+len, float_buff); - Steve Jessop
在这里使用std::copy暴露了STL(以及C ++)中的一个缺陷。当你复制某物时,它应该是真实的,即copy == original。通过依赖于隐式转换,这种情况不再成立,因此应避免使用隐式转换。 - Mark Ruzon
在这种情况下: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

0

没有人提到这一点,但如果你使用浮点数进行任何算术运算,你可能希望舍入而不是截断... 如果你有字符49,并且它被转换为4.9E1,经过一些算术运算后,它可能会变成4.89999999E1,当你将其转换回字符时,它将变成48。

如果你不对浮点数进行任何操作,这应该不是问题,那么你为什么需要它作为浮点数呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接