有没有可能将大端序的浮点数转换为小端序?我从一个PowerPC平台得到了一个大端序值,我要通过TCP发送给一个Windows进程(小端序)。这个值是一个浮点数,但是当我将值memcpy
到Win32浮点类型中,然后调用_byteswap_ulong
函数对该值进行字节交换时,我总是得到0.0000?我做错了什么?
有没有可能将大端序的浮点数转换为小端序?我从一个PowerPC平台得到了一个大端序值,我要通过TCP发送给一个Windows进程(小端序)。这个值是一个浮点数,但是当我将值memcpy
到Win32浮点类型中,然后调用_byteswap_ulong
函数对该值进行字节交换时,我总是得到0.0000?我做错了什么?
简单地反转四个字节就行了
float ReverseFloat( const float inFloat )
{
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];
return retVal;
}
char *
重新解释是被定义良好的(参见C++03 §3.10/15)。而联合体黑科技则不是(参见C++03 §9.5/1)。如果你熟悉这种语言,那么避免未定义或实现定义的行为并不特别困难。 - James McNellis这是一个可以反转任何类型字节顺序的函数。
template <typename T>
T bswap(T val) {
T retVal;
char *pVal = (char*) &val;
char *pRetVal = (char*)&retVal;
int size = sizeof(T);
for(int i=0; i<size; i++) {
pRetVal[size-1-i] = pVal[i];
}
return retVal;
}
我很久以前找到了类似的东西。虽然可以用来逗笑,但食用需谨慎。我甚至没有编译它:
void * endian_swap(void * arg)
{
unsigned int n = *((int*)arg);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
*arg = n;
return arg;
}
*arg = n;
?在没有进行强制类型转换的情况下,将值赋给已解引用的void指针是否有效?我预计编译器会报错。 - blubberdiblubfloat big2little (float f)
{
union
{
float f;
char b[4];
} src, dst;
src.f = f;
dst.b[3] = src.b[0];
dst.b[2] = src.b[1];
dst.b[1] = src.b[2];
dst.b[0] = src.b[3];
return dst.f;
}
根据jjmerelo的建议编写循环,更通用的解决方案可能是:
typedef float number_t;
#define NUMBER_SIZE sizeof(number_t)
number_t big2little (number_t n)
{
union
{
number_t n;
char b[NUMBER_SIZE];
} src, dst;
src.n = n;
for (size_t i=0; i<NUMBER_SIZE; i++)
dst.b[i] = src.b[NUMBER_SIZE-1 - i];
return dst.n;
}
不要直接将数据复制到float类型中。保持其为char数据,交换字节,然后将其视为float。
从 SDL_endian.h 中稍作修改:
std::uint32_t Swap32(std::uint32_t x)
{
return static_cast<std::uint32_t>((x << 24) | ((x << 8) & 0x00FF0000) |
((x >> 8) & 0x0000FF00) | (x >> 24));
}
float SwapFloat(float x)
{
union
{
float f;
std::uint32_t ui32;
} swapper;
swapper.f = x;
swapper.ui32 = Swap32(swapper.ui32);
return swapper.f;
}
_byteswap_ulong
时,我总是得到0.0000?@morteza和@AnotherParker已经提到了Boost库,指出对float
的支持已被删除。但是,自从他们发表评论以来,它已经在库的子集中重新添加了。
使用Boost.Endian转换函数,版本1.77.0,就像我写这篇答案一样,您可以执行以下操作:
float input = /* some value */;
float reversed = input;
boost::endian::endian_reverse_inplace(reversed);
查看常见问题解答以了解为什么支持被删除,然后部分添加回来(主要是因为反转的float
可能不再有效),并在此处查看支持历史记录。
float
如何在被具有相反字节序的系统交换其字节后变成NaN。常见问题解答中提到,即使整数和FP具有相同的字节序,这种情况也可能发生。但是,如果没有示例,我不会相信他们的说法。 - cesssamd64
系统(小端)上,四个字节7f ffffffa0 0 0
被解释为5.75752e-41
,但反转会给我一个信号NaN。 - vvanpeltfloat
存储为float
类型,所以我没想到这一点。当他们提到代码可能会生成NaN时,我认为他们指的是在传输结束时而不是在中途出现。谢谢! - cesss在某些情况下,特别是在Modbus上:浮点数的网络字节顺序为:
nfloat[0] = float[1]
nfloat[1] = float[0]
nfloat[2] = float[3]
nfloat[3] = float[2]
_byteswap_ulong
,会发生什么? - Maciej Hehlboost::endian
中的浮点支持已被移除,因为它无法正常工作。 - AnotherParker