大端小端区别
参考
大端是指低字节存储在高地址;小端存储是指低字节存储在低地址。下图为小端存储方式
以0x01234567为例,最高位为0x01,最低位为0x67,它的大端字节序和小端字节序的写法如下:
网络字节序采用大端字节序。
为什么有大小端
计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的,所以计算机的内部处理大都是小端字节序。
但是,人类还是习惯大端字节序。所以,除了计算机的内部处理,其他场合几乎都是大端字节序,比如网络传输和文件储存等。
如何判断大端存储还是小端存储
#include<iostream>
int check()
{
int t = 1;
//将t转化为char* 指针,然后在取前两位,如果是小端存储
//则值为0x56,如果是大端存储,则值为0x12
return *(char*)&t;
}
int main()
{
int i = check();
if (1 == i)
printf("是小端\n");
else if (1 != i)
printf("是大端\n");
system("pause");
return 0;
}
windows接口
将一个无符号长整型数从主机字节序转换成网络字节序
uint32_t htonl(uint32_t hostlong);
将一个无符号短整型数从主机字节序转换成网络字节序
uint16_t htons(uint16_t hostshort);
将一个无符号长整型数从网络字节序转换成主机字节序
uint32_t ntohl(uint32_t netlong);
将一个无符号短整型数从网络字节序转换成主机字节序
uint16_t ntohs(uint16_t netshort);
所在头文件和目录
#include<WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
直接内存修改
仅考虑一字节对齐情况
void convertByteSequence(char * pInfoUnitAddr ,QList<int> list )
{
char *iterAddr = pInfoUnitAddr; //小报文头首地址
for ( int i = 0 ; i < list.count() ; i++ )
{
convert(iterAddr, list.value(i));
iterAddr += list.value(i);
}
}
void convert(char *pData, int len)
{
for ( int i = 0 ; i < len/2 ; i++ )
{
char tmp = pData[i];
pData[i] = pData[len-1-i];
pData[len-1-i] = tmp;
}
}
大小端宏定义判断
个人感觉这种用法会比封装为函数每一次判断调用简单
如果满足 LittleEndian == 0x56 则为小端存储,否则为大端存储,则不需要进行网络字节序的转换
static int LittleEndian = (char)(0x123456);
#define ISLittleEndian (LittleEndian == 0x56)
附加嵌入式性质的结构体定义
以嵌入式形式按位运算与定义可以配合上述代码完成字符转换,但是可以解决位运算的痛苦;
以int大小为例
//注意:冒号后面的综合一定要等于sizeof(int)*8
struct MyStruct
{
int i1 : 8;//注意:这里是int中的第一位
int i2 : 8;
int i3 : 8;
int i4 : 8;//注意:这里是int中第32位
};