一、 字节序列大小端
如果将一个32位的整数0x87654321存放到一个整型变量(int) 中,这个整型变量采用大端或者小端模式在内存中的存储由下表所示。
地址偏移 | 大端模式 | 小端模式 |
---|---|---|
0x00 | 87 | 21 |
0x01 | 65 | 43 |
0x02 | 43 | 65 |
0x03 | 21 | 87 |
字节的大小端主要指的是字节存放的顺序, 小端的低位在低地址,高位在高地址。我们在手动拼接网络报文的时候,需要做大小端的转化,这里的转化指的就是字节序列
#include <stdio.h>
#include <stdbool.h>
bool isBigEndian() {
int a = 1;
return 0 == *((char *)(&a));
}
int main(int argc, char *argv[]) {
if (isBigEndian()) {
printf("big endian\n");
} else {
printf("little endian\n");
}
return 0;
}
二、 bit序列
位域会按照数据结构从低到高进行存储,与计算机的大小端无关。
#include <memory.h>
#include <stdbool.h>
#include <stdio.h>
struct A {
unsigned char a : 2;
unsigned char b : 3;
unsigned char c : 2;
unsigned char d : 1;
};
int main(int argc, char *argv[]) {
struct A a;
// 0000 0110
unsigned char c = 6;
memcpy(&a, &c, sizeof(a));
printf("a=%d, b=%d, c=%d, d=%d\n", a.a, a.b, a.c, a.d);
}
在小端机器上的输出为:
a=2, b=1, c=0, d=0
在大端机器上得输出为:
a=0, b=0, c=3, d=0
关于移位操作
int main(int argc, char *argv[]) {
int i = 1;
printf("%d\n", i << 1);
}
小端输出:
2
大端输出:
2
对于C语言的移位操作而言,左移动都表示扩大,右移动都表示缩小。
三、 使用qemu测试大小端
- 安装
qemu
支持mips
:
apt install qemu-user-static qemu-system-mips
- 安装编译
mips
的gcc
工具
apt install gcc-mips-linux-gnu
- 编写程序进行测试:
#include <stdio.h>
#include <endian.h>
int main()
{
int x = 0x1234;
printf("0x%x, htole32 0x%x, htobe32 0x%x\n", x, htole32(x), htobe32(x));
return 0;
}
- 编译,可看出编译出的程序时MSB,大端序的。需要注意的是要加上
-static
的编译选项否则运行时候会提示找不到链接库。
mips-linux-gnu-gcc -static xx.c
[root@ubuntu] ~
$ file a.out
a.out: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=48929411066f86d58ed7855e545b980bc92fd75b, not stripped