首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >大小端,你应该知道的,这篇文章讲全了

大小端,你应该知道的,这篇文章讲全了

作者头像
程序员的园
发布2024-11-22 18:32:47
发布2024-11-22 18:32:47
82500
代码可运行
举报
运行总次数:0
代码可运行

1. 引言

在计算机中,大小端描述了多字节数据在内存中的存储顺序。理解和正确处理大小端问题是编写健壮跨平台程序的关键。本文将全面介绍大小端的基本概念、判断方法、应用场景及注意事项,结合全样本数据分析哪些数据受大小端影响并给出处理方法。

2. 基本概念

计算机内存按字节划分为连续的线性地址空间。当存储多字节数据时,不同的存储顺序形成两种主要模式:

  • 大端(Big-Endian):高字节存储在低地址,低字节存储在高地址。
  • 小端(Little-Endian):低字节存储在低地址,高字节存储在高地址。

注意

  • 大小端主要取决于计算机的硬件架构,与操作系统的具体实现关联较少。
  • 当且仅当存储多字节数据时才需考虑大小端问题,例如 int、float、double、uint16_t 及其数组,甚至是 uint32_t 类型的数组。
  • 普通单字节数据类型如 char 和 uint8_t 及其数组不需要考虑大小端问题。需要注意,宽字符(如 wchar_t)或多字节字符序列可能受大小端影响,应单独处理。

数据示例

代码语言:javascript
代码运行次数:0
运行
复制
#include <cstdint>
#include <iostream>
uint8_t u8 = 0x12; // 单字节数据
uint32_t u32 = 0x12345678; // 多字节数据
uint8_t array_u8[] = {0x12, 0x34, 0x56, 0x78}; // 单字节数组
uint32_t array_u32[] = {0x12345678, 0x9abcdef0}; // 多字节数组
  • uint8_t u8:单字节数据,存储时不涉及字节序,不受大小端影响。
  • uint32_t u32:多字节数据,其字节存储顺序在大小端中不同。受大小端影响。
    • 小端:78 56 34 12
    • 大端:12 34 56 78
  • uint8_t array_u8[]:单字节数组,每个元素单独存储,不受字节序影响,不受大小端影响。
    • 内存表示在大小端均为:12 34 56 78。
  • uint32_t array_u32[]:多字节数组,每个元素的字节顺序在大小端中不同。受大小端影响
    • 小端:78 56 34 12,f0 de bc 9a
    • 大端:12 34 56 78,9a bc de f0

3. 判断方法

不同平台的大小端顺序可能导致二进制文件和网络传输的解析错误。因此,跨平台存储/解析数据时需要依据本机的架构的大小端类型进行调整,为此需要判断本机的大小端类型。如下为判断方法:

3.1 借助联合体判断

通过联合体访问不同表示方式的多字节数据:

代码语言:javascript
代码运行次数:0
运行
复制
bool isLittleEndian() 
{
  union {
  uint32_t i;
  uint8_t c[4];
  } test = {0x01020304};
  return test.c[0] == 0x04;
}

3.2 借助标准库宏__BYTE_ORDER

利用系统头文件中的预定义宏:

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__)
#include <endian.h>
#elif defined(_WIN32)
#include <winsock2.h>
#endif
bool isLittleEndian() 
{
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
  return true;
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
  return false;
#else
  #error "Cannot determine endianness"
#endif
}

3.3 C++20标准库支持

C++20引入了std::endian用于判断系统字节序:

代码语言:javascript
代码运行次数:0
运行
复制
#include <bit>
bool isLittleEndian()
{
  return  (std::endian::native == std::endian::little);
}

4. 数据转换

已知数据存储的类型和计算机本身的大小端类型时,类型匹配时,无需转换;否则需要进行转换。转换方法如下:

代码语言:javascript
代码运行次数:0
运行
复制
uint32_t swapEndian(uint32_t value) 
{
return ((value >> 24) & 0xFF) |
  ((value >> 8) & 0xFF00) |
  ((value << 8) & 0xFF0000) |
  ((value << 24) & 0xFF000000);
}

注意

频繁进行大小端转换可能影响性能,尤其在资源受限的嵌入式设备上。

5. 总结

大小端是描述多字节数据存储顺序的重要概念,对跨平台数据传输、文件解析和网络通信有重要影响。单字节数据及数组不受大小端影响,可直接操作。多字节数据及数组受大小端影响,需特别处理。通过全面了解大小端特性及其影响,开发者可以更好地构建高效、可靠的跨平台程序。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档