其他分享
首页 > 其他分享> > 【转】大小端序与端序转换(一)

【转】大小端序与端序转换(一)

作者:互联网

最近在做项目的时候,遇到了一家厂商采用的端序与以往不同,废了一番周折,在这里总结一下

大端序和小端序的概念

我们知道,计算机在存储数据时,是以字节为单位的,每个地址对应一个字节。但在现代编程语言中,使用的数据类型往往需要1、2、4、8个字节,那么就涉及到这些数据在内存中如何存储的问题。除此之外,不同位数的处理器(如16位、32位、64位)其寄存器的宽度也不同,因此也会涉及到字节顺序的问题。不同的处理器或者不同的应用对字节顺序的不同处理,就催生出了大小端序的概念。

所谓大端序(Big-endian),即在数据存储时,数据的高位字节存放在内存的低地址端,而数据的低位字节存放在内存的高地址端;

小端序(Little-endian)则相反,数据的高位字节存放在内存的高地址端,数据的低位字节存放在内存的低地址端。

注意,无论大端序还是小端序,单个字节内部的bit顺序是一致的。

大端序与人们对数字的书写顺序一致,例如一个32位的整型数据0x12345678,如果使用大端序,其在内存中的存储顺序如下,其中p表示起始地址。
image
如果将0x12345678使用小端序存储,则存储顺序如下图所示:
image

一般情况下,我们常用的X86架构的处理器都是小端序,而通信协议一般选择大端序(因此,大端序也常称为网络字节序),当然,有些ARM处理器可以工作在大端模式,也可以工作在小端模式。

大小端序之间的转换

了解了大小端序的概念,那么我们就可以针对具体的端序问题,通过转换的方式进行解决。在本文一开始提到,两个厂商的相机输出的字节序不一致的问题,表现为32位float型数据,传输到本地服务器时,有一家相机的数据依然是按照大端序存储的,因此导致运算出错。我们尝试对数据进行转换。由于是float类型,float类型在内存中的存储较复杂,因此我们借助联合体,通过对32位int型数据的转换,实现对32为float类型数据的转换。
了解了大小端序的概念,那么我们就可以针对具体的端序问题,通过转换的方式进行解决。在本文一开始提到,两个厂商的相机输出的字节序不一致的问题,表现为32位float型数据,传输到本地服务器时,有一家相机的数据依然是按照大端序存储的,因此导致运算出错。我们尝试对数据进行转换。由于是float类型,float类型在内存中的存储较复杂,因此我们借助联合体,通过对32位int型数据的转换,实现对32为float类型数据的转换。

union union32IntFloat
{
	int32_t i_32;
	float f_32;
};
 
/* Swap bytes order for int32_t value */
int32_t bytes_swap_int32(int32_t int_value)
{
	int32_t int_swapped = ((int_value & 0x000000FF) << 24 |
							(int_value & 0x0000FF00) << 8 |
							(int_value & 0x00FF0000) >> 8 |
							(int_value & 0xFF000000) >> 24);
							
	return int_swapped;
}
 
/* Swap bytes order for float32 value */
float bytes_swap_float32(float value)
{
	union32IntFloat u_value;
	u_value.f_32 = value;
	
	u_value.i_32 = bytes_swap_int32(u_value.i_32);
	
	return  u_value.f_32;  
}

测试程序:讲一个大端序存放的数字转换成小端序之后输出

int main()
{
	float ori_float = -16223553;   //F4 F7 8D 41
	float swapped_float = bytes_swap_float32(ori_float);
 
	std::cout << "Before swap: " << ori_float << ", after swap: " << swapped_float << std::endl;
 
	return 0;
}

执行的结果如下:
image

标签:端序,大端序,转换,字节,32,float,value,大小
来源: https://www.cnblogs.com/sggggr/p/16381827.html