【词条】大端(big-endian)模式和小端(little-endian)模式

本文介绍了大端模式和小端模式的概念及其在计算机内存中的表现形式,并探讨了它们是如何由CPU决定的,还讨论了比特序的存在与否以及如何通过简单程序判断当前CPU的字节序。

1、我们知道当定义一个变量的时候,操作系统会为这个变量分配一段内存,具体分配哪段内存由操作系统的内存分配策略决定。

例如short int x = 0x1234;(为了好理解,我们这里使用16进制表示)

这个时候操作系统会为x分配两个字节的内存(假设为0x4000、0x4001这两个地址)

(1)如果x在内存中按照下面的方式存储

内存地址

0x4000

0x4001

存放内容

0x12

0x34

那么它就是大端(big-endian)模式。
(2)如果x在内存中按照下面的方式存储

内存地址

0x4000

0x4001

存放内容

0x34

0x12

那么它就是小端(little-endian)模式。
可见,大端模式是符合我们人类思维习惯的。
 
总结:所谓big-endian是指低位内存地址存放最低有效字节(LSB);big-endian是指低位内存地址存放最高有效字节(MSB)。
 
2、大端模式、小端模式是由什么决定的呢?
答:谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。
      C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。可见,大端模式、小端模式是有处理器(CPU)决定的,而编译器在生成程序的时候,又可能会改变这种模式。
 
3、什么是网络字节序?
答:所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。
 
4、再来谈点深入的,大端、小端模式实际上是CPU在存储不同字节的数据时的顺序问题,那么CPU在存储一个字节的数据时其字节内的8个比特之间的顺序是否也有littele-endian和big-endian只分呢,或者说比特序是否有不同?
答:实际上,这个比特序是同样存在的。下面以数字0xB4(10110100)用图加以说明。
                  Big Endian
                              msb                                                        lsb
                            ---------------------------------------------->
                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                               | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                  Little Endian
                             lsb                                                            msb
                             ---------------------------------------------->
                            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
                            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           实际上,由于CPU存储数据操作的最小单位是一个字节,其内部的比特序是什么样对我们的程序来说是一个黑盒子。也就是说,你给我一个指向0xB4这个数的指针,对于big endian方式的CPU来说,它是从左往右依次读取这个数的8个比特;而对于little endian方式的CPU来说,则正好相反,是从右往左依次读取这个数的8个比特。而我们的程序通过这个指针访问后得到的数就是0xB4,字节内部的比特序对于程序来说是不可见的。
 
5、如何确定CPU的字节序是大端模式还是小端模式呢?
答:
         short int i = 0x1234;
	char x = 0x12;
	char y = 0x34;

	char c = *(char *)&i;

	//低位地址存放的是最高有效字节
	if (x == c)
	{
		cout << "big endian" << endl;
	}

	//低位地址存放的是最低有效字节
	if (y==c)
	{
		cout << "little endian" << endl;
	}
还有一个程序相当有趣,可以用来判断大小模式,它用到了联合体的特性
int main()
{
	union
	{
		short int i;
		char c;
	}u;

	u.i = 1;

	if (u.c == 1)
	{
		cout << "little endian" << endl;
	}

	if (u.c == 0)
	{
		cout << "big endian" << endl;
	}

还有一个联合体的程序,也很有趣
int main()
{
	union
	{
		long l;
		char c[sizeof(long)];
	}u;

	u.l = 1;
	if(u.c[sizeof(long)-1] == 1)
	{
		cout << "big endidan" << endl;
	}

	if (u.c[0] == 1)
	{
		cout << "little endian" << endl;
	}
}

 
在 C 语言中,判断系统是 **大端Big-endian)** 还是 **小端Little-endian)**,可以通过检查一个多字节数据在内存中的存储顺序来实现。 --- ## ✅ 方法一:使用联合体(Union)判断字节序 ```c #include <stdio.h> int main() { union { unsigned int i; unsigned char c[sizeof(unsigned int)]; } test; test.i = 0x01020304; if (test.c[0] == 0x01) { printf("Big-endian\n"); } else if (test.c[0] == 0x04) { printf("Little-endian\n"); } else { printf("Unknown endianness\n"); } return 0; } ``` ### 解释: - 联合体 `test` 中的 `i` `c[]` 共享同一块内存。 - 将 `i` 设置为 `0x01020304`,它是一个 4 字节的整数。 - 如果系统是 **小端模式**,最低有效字节存在低地址,即 `c[0] = 0x04`。 - 如果是 **大端模式**,最高有效字节存在低地址,即 `c[0] = 0x01`。 --- ## ✅ 方法二:使用指针方式判断字节序 ```c #include <stdio.h> int main() { unsigned int i = 0x01020304; unsigned char *c = (unsigned char *)&i; if (*c == 0x01) { printf("Big-endian\n"); } else if (*c == 0x04) { printf("Little-endian\n"); } else { printf("Unknown endianness\n"); } return 0; } ``` ### 解释: - 用指针指向 `i` 的第一个字节。 - 同样根据第一个字节的值判断大小端--- ## ✅ 方法三:封装为函数(便于复用) ```c #include <stdio.h> int is_little_endian() { int i = 1; return *((char *)&i) == 1; } int main() { if (is_little_endian()) { printf("System is Little-endian\n"); } else { printf("System is Big-endian\n"); } return 0; } ``` ### 解释: - `int i = 1`,其十六进制为 `0x00000001`。 - 如果系统是小端,第一个字节就是 `0x01`,返回真。 - 如果是大端,第一个字节是 `0x00`,返回假。 --- ## ✅ 总结 | 方法 | 说明 | 可移植性 | 推荐程度 | |------|------|----------|----------| | 使用联合体 | 简洁直观 | 高 | ⭐⭐⭐ | | 使用指针 | 更通用 | 高 | ⭐⭐⭐⭐ | | 封装为函数 | 易于复用 | 高 | ⭐⭐⭐⭐⭐ | --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值