一、大小端的定义
大端模式(Big-Endian
),是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式(Little-Endian
),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
二、字节序
在搞清楚大小端之前先搞清楚字节序,否则会导致很多人无法理解程序中的读取顺序。
字节序就是数据存放的顺序。当数据仅有1字节时,计算机无需考虑字节存放顺序;但当数据大于1字节时,就必须考虑如何存放了(先放高字节还是低字节),如十六进制数0x12345678,按人类阅读习惯,左起为高字节,右起为低字节
|高字节--------------->低字节|
|------|------|------|------|
| 0x12 | 0x34 | 0x56 | 0x78 |
|------|------|------|------|
三、大小端原理
1、大端序
符合人的阅读习惯,低字节存放在高地址,高字节存放在低地址,即内存排布如下:
|高字节--------------->低字节|
|------|------|------|------|
| 0x12 | 0x34 | 0x56 | 0x78 |
|------|------|------|------|
|低地址--------------->高地址|
2、小端序
低字节存放在低地址,高字节存放在高地址,即内存排布如下:
|低字节--------------->高字节|
|------|------|------|------|
| 0x78 | 0x56 | 0x34 | 0x12 |
|------|------|------|------|
|低地址--------------->高地址|
四、示例
1、判断大小端
BOOL IsBigEndian()
{
int a = 0x1234;
char b = *(char *)&a; //通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分
if( b == 0x12)
{
return TRUE;
}
return FALSE;
}
void main(void){
int ret = -1;
ret = IsBigEndian();
if (ret == TRUE){
printf("big\n");
else
printf("little\n")
)
)
2、大小端转序
对于字数据(16位):
#define BigtoLittle16(A) (( ((uint16)(A) & 0xff00) >> 8) | \
(( (uint16)(A) & 0x00ff) << 8))
对于双字数据(32位):
#define BigtoLittle32(A) ((( (uint32)(A) & 0xff000000) >> 24) | \
(( (uint32)(A) & 0x00ff0000) >> 8) | \
(( (uint32)(A) & 0x0000ff00) << 8) | \
(( (uint32)(A) & 0x000000ff) << 24))
数值四则运算计算的是字节序,从低位逐渐开始增加。
大小端问题主要涉及的是非单字节非字符串外的其余数据的表示和传递,如short型、int型等。大端和小端有其各自的优势。我们知道计算机正常的内存增长方式是从低到高(当然栈不是),取数据方式是从基址根据偏移找到他们的位置,从他们的存储方式可以看出,大端存储因为第一个字节就是高位,从而很容易知道它是正数还是负数,对于一些数值判断会很迅速。而小端存储 第一个字节是它的低位,符号位在最后一个字节,这样在做数值四则运算时从低位每次取出相应字节运算,最后直到高位,并且最终把符号位刷新,这样的运算方式会更高效。