大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
(1)为什么会有大小端之分?
因为在计算机系统中,是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit. 在C中除了char的8位,short的16位(具体大小多少要看编译器,就像32位和64位系统,所占大小是不一样的),另外对于位数大于8 位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
例如一个16bit的short x,若在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86系统是小端模式。
内存中地址在这种表示法从左往右,由低地址到高地址。
(2)判断大小端
可用共用体判断:
int fun()
{
union test
{
int a;
char ch;
}a;
a.a = 1;
return (a.ch == 1)
}
令a = 1, 即为0x00000001。
然后只要判断a.ch 是否为真,若是则为小端,不是则为大端,因为不管大端小端,存地址都是从首位开始存放。
(3)将整型数据按位逆序
主要想考的就是位运算的使用,就是怎么把一个整数的高低位的数值调用。
即:如果输入1,即0001,应该输出1000,即8。如果输出257,即0010 0101 0111,应该输出0100 1010 1110
#ifndef INTERVIEW_BIG_LITTLE_H
#define INTERVIEW_BIG_LITTLE_H
typedef unsigned short int uint16;
typedef unsigned long int uint32;
#define swp16(x) \
(((short)(x) & (short)0x00ff) << 8) | \
(((short)(x) & (short)0xff00) >> 8)
#define Swap32(A) \
( (((uint32)(A) & (0xff000000)) >> 24) | \
(((uint32)(A) & (0x00ff0000)) >> 8) | \
(((uint32)(A) & (0x0000ff00)) << 8) | \
(((uint32)(A) & (0x000000ff)) << 24) )
#endif //INTERVIEW_BIG_LITTLE_H
假设x=0xaabb
那(short)(x) & (short)0x00ff) ,就先将16位数高8位置0,成了0x00bb, 然后<<8 向左移8位后,低8位变成了高8位,低8位补0 结果为 0xbb00,后面一样
(4)按字节逆序
下面用宏实现:
#define Swap16(a) \
((((a) & 0xff) << 8) | (((a) >> 8) & 0xff))
#define Swap32(a) \
(((a) >> 24) | (((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | ((a) << 24))
#define Swap64(a)
(((a) >> 56) | \
(((a) & 0x00ff000000000000) >> 40) | \
(((a) & 0x0000ff0000000000) >> 24) | \
(((a) & 0x000000ff00000000) >> 8) | \
(((a) & 0x00000000ff000000) << 8) | \
(((a) & 0x0000000000ff0000) << 24) | \
(((a) & 0x000000000000ff00) << 40) | \
(((a) << 56)))
vs2012以上提供ntohs、htons、ntohl、htonl这4个函数,已实现16位和32位本地字节序的大小端转换