admin管理员组文章数量:1443571
[c语言日寄MAX]深度解析:大小端字节序
前言
大小端字节序是什么?怎么通过程序判断机器是大端还是小段?全局变量和局部变量对大小端的判断有影响吗?本文将为你带来深度的大小端字节序解析,力求一文解决全部疑问。
一、什么是大小端字节序?
大小端字节序是计算机中存储 多字节数据时字节的排列顺序。它们是两种不同的存储方式。
1. 书面定义
大端字节序(Big-Endian)
- 定义:大端字节序是指在多字节数据中,高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。也就是说,数据的最高有效字节(MSB)存储在地址最低的位置,最低有效字节(LSB)存储在地址最高的位置。
小端字节序(Little-Endian)
- 定义:小端字节序是指在多字节数据中,低位字节存放在内存的低地址端,高位字节存放在内存的高地址端。也就是说,数据的最低有效字节(LSB)存储在地址最低的位置,最高有效字节(MSB)存储在地址最高的位置。
2.直观理解
我们假设有这样一段由低地址到高地址的内存,每一个格子代表1字节
:
现在,我们要将一个有符号整形(int)数据储存在里面。
小端字节序按照“高对高,低对低”的顺序排列。 所谓“高对高,低对低”意思是:高地址存放高位数据,低地址存放低位数据。
而大端则是反过来,”低对高,高对低“。 意思是:低地址存放高位数据,高地址存放低位数据。
高位数据和低位数据
高地址我们知道是哪里,但是什么是高位数据呢?什么又是低位数据呢? 我们看这样一个例子:
可以看到,对于一个整形数字“2147483649”而言,哪些是低位,哪些是高位。 也就是:高位代表权重更高的比特位,低位代表权重低的比特位。 对于这个数据, 低位的”1“是2^0,计入的值是1。 而高位的”1“是2^31,计入的值为2147483648。
大小端对比
知道了排序规则和高位和低位的定义,我们就可以知道大、小端机器怎么存放多字节数据。 我们将内存映射出来,把他们的数据放在一起对比:
结合这张图,我们就可以理解大、小端字节序的区别。
值得注意的是: 我们发现,在图中的数据,大小端的区别只在字节层面上。 而字节之下:字节内部 比特位 的排列顺序没有被改变。
二、怎么写程序判断机器是大端还是小端?
指针
在写这个程序之前,我们需要知道计算机是怎么读取数据的。 对于c语言而言,读取内存需要一个指针,这个指针存放着数据在内存中的地址。
结合这张图,我们知道,无论是大端还是小端,指向数据的指针,都在低地址位。
数据的类型会影响指向数据的指针位置吗?
不会。 我们知道,数据一般分为两种,一种是变量数据,一种是动态内存分配的数据。
动态内存分配
我们知道,动态内存规划分配的内存储存在”堆“中,而堆的使用习惯是优先使用低地址位。 如果我们要动态内存分配一个整形数据,那么内存开辟是这样的:
可以看到,我们在低地址已经使用的内存之后开辟了4个字节的内存。 这个新数据的指针如图:
没错,此时的指针指向的依旧是数据的低地址处。
变量数据
再来看看变量数据。 变量数据储存在”栈“中,而栈的使用习惯是先使用高地址,再使用低地址。 如果我们要开辟一个整形变量,那么它在内存中是这样操作的:
这个变量数据的指针是这样的:
总结:无论是变量还是动态内存分配的数据,指针位置都是低地址处。
基础判断函数
想要判断大小端,只需要判断指针位置对应的字节就可以了。
那么,思路就是:
- 设置一个无符号整形(unsigned int)变量,赋值“1”。(往内存中存入数据)
- 强制类型转换为无符号字符(unsigned char)类型(只读取第一个字节的数据)
- 判断数据是0,还是1。(0就是小端,1就是大端)
解决方案如下:
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
// 函数声明:判断系统是大端字节序还是小端字节序
int isLittleEndian() {
// 定义一个无符号整型变量,赋值为1
unsigned int x = 1;
// 将x的地址强制转换为unsigned char指针
// 这样可以逐字节访问x的内存
unsigned char* bytePointer = (unsigned char*)&x;
// 检查x的第一个字节(最低地址的字节)
// 如果x的值为1,那么在小端字节序下,第一个字节为1
// 在大端字节序下,第一个字节为0
if (bytePointer[0] == 1) {
// 如果第一个字节为1,说明是小端字节序
return 1;
} else {
// 否则是大端字节序
return 0;
}
}
int main() {
// 调用函数判断字节序
if (isLittleEndian()) {
printf("System is Little Endian.\n");
} else {
printf("System is Big Endian.\n");
}
return 0;
}
联合体判断法
使用联合体(union)也可以实现判断大小端字节序的功能。 基于联合体的解决方案如下:
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
// 定义一个联合体,包含一个无符号整型和一个无符号字符数组
union EndianChecker {
unsigned int value; // 用于存储整数值
unsigned char bytes[sizeof(unsigned int)]; // 用于逐字节访问value的内存
};
// 函数声明:判断系统是大端字节序还是小端字节序
int isLittleEndian() {
// 创建一个联合体变量
union EndianChecker checker;
// 将联合体的value成员赋值为1
checker.value = 1;
// 检查联合体的bytes数组的第一个字节
// 如果是小端字节序,第一个字节(最低地址的字节)为1
// 如果是大端字节序,第一个字节为0
if (checker.bytes[0] == 1) {
// 如果第一个字节为1,说明是小端字节序
return 1;
} else {
// 否则是大端字节序
return 0;
}
}
int main() {
// 调用函数判断字节序
if (isLittleEndian()) {
printf("System is Little Endian.\n");
} else {
printf("System is Big Endian.\n");
}
return 0;
}
总结
大小端字节序是针对“字节”的排序,和bit的排序无关,和数据类型无关。 我们可以使用指针+强制类型转换法实现大小端字节序的判定,也可以使用联合体实现。
关注窝,每三天至少更新一篇优质c语言题目详解~ 本文手工制作,如果对你有帮助,欢迎点赞收藏和评论~
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-03-25,如有侵权请联系 cloudcommunity@tencent 删除内存数据指针max变量本文标签: c语言日寄MAX深度解析大小端字节序
版权声明:本文标题:[c语言日寄MAX]深度解析:大小端字节序 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1748145316a2815862.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论