前言
这是一个古老而基础的问题,小代码,能够解决大问题。大框架的问题,就藏在小细节中。越大的框架,这种小细节藏的越深。为什么要区分大小端模式?难道不会有中端模式吗?
一 基本原理与内存图
下面的内存视图的地址是递增的。
例如一个32位整形
uint32_t num = 0x12345678;
采用大端模式存储的内存视图:
0x80000001: 12 34 56 78 00 00 00 00 00 00 00 00 00 00 00 00
也可以做写作:
0x80000001: 12
0x80000002: 34
0x80000003: 56
0x80000004: 78
采用小端模式存储的内存视图:
0x80000001: 78 56 43 12 00 00 00 00 00 00 00 00 00 00 00 00
相对清晰的视图
0x80000001: 78
0x80000002: 56
0x80000003: 43
0x80000004: 12
二 使用指针验证大小端模式
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint32_t num = 0x12345678;
uint8_t *c = (uint8_t*)#
int i = 0;
printf("c = 0x%x\n",*c);
if(*c == 0x12){
printf("big endian\n");
}else if(*c == 0x78){
printf("little endian\n");
}else{
printf("error\n");
}
for(i = 0;i < sizeof(uint32_t);i++){
printf("c[%d]=0x%x ",i,c[i]);
}
printf("\n");
return 0;
}
测试结果:如果输出0x78,那就是小端模式,如果输出0x12那就是大端模式。
lkmao@ubuntu:~$ ./a.out
c = 0x78
little endian
lkmao@ubuntu:~$
二 使用共用体验证大小端模式
#include <stdio.h>
#include <stdint.h>
union endian{
uint32_t num;
uint8_t c;
};
int main(void)
{
union endian e;
e.num = 0x12345678;
printf("e.c = 0x%x\n",e.c);
printf("e.num = 0x%x\n",e.num);
if(e.c == 0x12){
printf("big endian\n");
}else if(e.c == 0x78){
printf("little endian\n");
}else{
printf("error\n");
}
return 0;
}
测试结果
lkmao@ubuntu:~$ ./a.out
e.c = 0x78
e.num = 0x12345678
little endian
lkmao@ubuntu:~$
四 相对正规的写法
在该示例中,is_little_endian函数中定义了一个匿名共用体,并定义了一个共用体变量e。如果e.c等于1则返回为真,属于小端模式,否则就是大端模式。
#include <stdio.h>
#include <stdint.h>
int is_little_endian(void)
{
union {
uint32_t num;
uint8_t c;
}e;
e.num = 1;
return e.c;
}
int main(void)
{
if(!is_little_endian()){
printf("big endian\n");
}else{
printf("little endian\n");
}
return 0;
}
二维地址空间就是二维存储空间吗?
我们熟知的内存计算策略是二元的,要么向左(递减),要么向右(递减)。在很久以前,经常使用两个8位的内存芯片级联为一个16位的内存芯片,在CPU中存储的16位数据,很可能高8位数据存放在内存芯片1,而低八位数据存放在内存芯片2。在地址空间上,他们是连续的,在存储空间上,他们是分别位于两颗不同的芯片。类似的原理在数据库中叫分片存储。
小结
。。。