前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >详解字节序,一文即懂!

详解字节序,一文即懂!

作者头像
Linux兵工厂
发布2024-03-18 17:18:49
5480
发布2024-03-18 17:18:49
举报
文章被收录于专栏:Linux兵工厂

START

Hi,大家好!最近工作中有同事问到字节序的问题,并且因为对字节序理解片面产生了一些编程上的问题。所以,借这个机会整理了这篇文章,希望能加深大家对字节序问题的理解。

  • 我们平时在写应用层程序时,一般不需要考虑字节序问题,因为字节序跟操作系统和硬件环境有关。而我们编写的程序很多情况下不需要跨平台,或者即使跨平台大都是一样的字节序(小端)。
  • 但是当我们编写网络通信程序,就必须要考虑字节序问题,因为你的数据在这样的场景下要跨平台,必须解决不同系统、不同平台的字节序问题。
  • 本章目录

unsetunset1、什么是字节序unsetunset

  • 当字节数大于1时需要考虑字节序(只有一个字节的情况下,比如char类型,也就不存在顺序问题啦)。
  • 多字节数据在内存中被存储为连续的字节序列,从低地址内存开始存储。例如0x87654321在内存可以从低位到高位顺序存储,也可以从高位到地位顺序存储。

字节序分类

  • 大端字节序所谓大端字节序就是从内存连续存储时高位在前,低位在后。即低地址内存存高位字节,高地址内存存低位字节。
  • 小端字节序所谓小端字节序就是从内存连续存储时低位在前,高位在后。即低地址内存存低位字节,高地址内存存高位字节。

名字由来

"大端"和"小端"这两个术语的由来据说源于《格列佛游记》(Gulliver's Travels)一书,作者是爱尔兰作家乔纳森·斯威夫特(Jonathan Swift),书中描绘了两个敌对国家之间的争议,该争议起源于吃蛋的方式。

在书中,主人公吉列佛·盖博是一个英国船长,他在一次航海中被风暴吹到了拉普图,这是一个由两个敌对国家组成的岛屿。这两个国家是博尔纳巴和利里巴。争议的起因是如何打破硬煮蛋的问题,这导致了两个国家的敌对。

  • 博尔纳巴(Big-Endian): 博尔纳巴人认为应该从蛋的大端砸开,因为这样可以保证蛋壳上的裂纹最小,蛋液不易溅出。
  • 利里巴(Little-Endian): 利里巴人则主张从蛋的小端砸开,他们认为这样更加方便,蛋壳碎片不易混入蛋液。

这个寓言故事中的争议象征着当时英国和法国之间的宗教和政治冲突,而在计算机科学领域,这个故事的概念被引用用来描述多字节数据在内存中的存储方式,即大端字节序和小端字节序。

因此,"大端"和"小端"这两个术语在计算机领域的使用,是借用了《格列佛游记》中的这个寓言故事,用来描述多字节数据中字节的存储顺序。

unsetunset2、字节序优缺点unsetunset

大端字节序(Big-Endian)和小端字节序(Little-Endian)是描述多字节数据在内存中存储顺序的两种方式。

优缺点

大端字节序
  • 优点:
    1. 易于阅读:在内存中,数据的高位字节位于低地址,符合人类的阅读习惯。
  • 缺点:
    1. 不利于低级别的存储与读取:对于一些底层的操作,例如位操作,需要更多的指令来处理。
小端字节序
  • 优点:
    1. 简化低级别的操作:对于一些低级别的操作,例如在整数的最低位进行位操作,更加方便。
  • 缺点:
    1. 阅读困难:在内存中,数据的高位字节位于高地址,不符合人类的阅读习惯,调试时可能会有一些困难。

选择标准

  • 硬件架构: 大部分个人计算机和服务器采用小端字节序,而一些大型机器和网络设备采用大端字节序。
  • 通信标准: 在网络通信中,通常使用大端字节序(网络字节序)。
  • 处理器设计: 处理器的设计也会影响字节序的选择。

前面说过,在实际应用中很多情况下字节序并不会引起问题,但在一些特定的场景,例如网络通信、数据存储和处理器指令集等方面,正确处理字节序是非常重要的。

unsetunset3、常见系统字节序unsetunset

常见的操作系统和芯片可以使用大端字节序(Big-Endian)或小端字节序(Little-Endian),这取决于它们的设计和架构。

操作系统

  1. Windows:
    • Windows x86和x86-64架构使用小端字节序。
  2. Linux:
    • 大多数Linux系统(如x86和x86-64架构)采用小端字节序。
  3. macOS:
    • macOS运行在x86-64架构上,使用小端字节序。
  4. UNIX:
    • 大多数UNIX系统,包括Solaris和AIX,也使用小端字节序。

芯片架构

  1. x86和x86-64:
    • 这是Intel和AMD处理器常见的架构,它们使用小端字节序。
  2. ARM:
    • 大多数ARM处理器使用小端字节序,但某些特定的ARM处理器支持可配置的字节序。
  3. MIPS:
    • MIPS处理器可以配置为使用大端或小端字节序,具体取决于硬件设计。
  4. PowerPC:
    • PowerPC处理器可以配置为使用大端或小端字节序,根据系统和应用需求。

unsetunset4、系统字节序判断unsetunset

在C语言中,要判断系统的字节序,一种常见的方法是通过检查一个整数的存储方式来确定。以下是一个简单的示例:

代码语言:javascript
复制
#include <stdio.h>

int main() {
    // 定义一个16位整数
    unsigned short int num = 1;

    // 将整数的地址转换为字符指针
    char *ptr = (char *)&num;

    // 判断字节序
    if (*ptr == 1) {
        printf("Little-Endian\n");
    } else {
        printf("Big-Endian\n");
    }

    return 0;
}

在这个例子中,我们定义了一个16位的整数 num,然后通过将其地址转换为字符指针 ptr,我们可以检查指针指向的内存中第一个字节的值来确定字节序。如果第一个字节的值是1,那么就是小端字节序;如果是0,则是大端字节序。

请注意,这种方法的可移植性可能不够好,因为它依赖于编译器的实现和系统的特定行为。更可靠的方法是使用头文件中定义的预处理器宏,例如 <endian.h> 中的 BYTE_ORDER 宏。在这个头文件中,BYTE_ORDER 可以是 __ORDER_LITTLE_ENDIAN____ORDER_BIG_ENDIAN____ORDER_PDP_ENDIAN__ 中的一个,分别表示小端、大端和PDP端字节序。以下是一个使用头文件的示例:

代码语言:javascript
复制
#include <stdio.h>
#include <endian.h>

int main() {
    #if BYTE_ORDER == __LITTLE_ENDIAN
        printf("Little-Endian\n");
    #elif BYTE_ORDER == __BIG_ENDIAN
        printf("Big-Endian\n");
    #else
        printf("Unknown Endian\n");
    #endif

    return 0;
}

使用预处理器宏更可移植,因为它们是由编译器提供的。更推荐此方法

unsetunset5、网络字节序unsetunset

网络字节序(Network Byte Order)是一种标准化的字节序,用于在计算机网络中传输数据。网络字节序通常采用大端字节序(Big-Endian)。在网络通信中,确保发送和接收端使用相同的字节序是非常重要的,以避免数据解释错误。

以下是关于网络字节序的一些详解:

特点和标准

  1. 大端字节序: 在网络字节序中,数据的高字节保存在内存的低地址,低字节保存在高地址。这种规定有助于不同体系结构的计算机在网络上传输数据时能够正确解释字节序。
  2. 标准: 网络字节序的标准由互联网工程任务组(IETF)制定,它在网络协议中被广泛使用,例如在TCP和UDP协议的头部中。

字节序转换

在进行网络通信时,为确保数据在不同主机之间正确解释,可能需要进行字节序的转换。通常,发送端在发送数据之前将其转换为网络字节序,而接收端在接收数据后将其转换为本地字节序。

在C语言中,可以使用库函数 htonlhtonsntohlntohs 来进行字节序的转换:

  • htonl(Host to Network Long):将32位整数由主机字节序转换为网络字节序。
  • htons(Host to Network Short):将16位短整数由主机字节序转换为网络字节序。
  • ntohl(Network to Host Long):将32位整数由网络字节序转换为主机字节序。
  • ntohs(Network to Host Short):将16位短整数由网络字节序转换为主机字节序。

示例:

代码语言:javascript
复制
#include <stdio.h>
#include <arpa/inet.h>

int main() {
    uint32_t localValue = 0x12345678; // 305419896 in decimal

    // 将主机字节序转换为网络字节序
    uint32_t networkValue = htonl(localValue);

    printf("Local Value: %08x\n", localValue);
    printf("Network Value: %08x\n", networkValue);

    // 将网络字节序转换为主机字节序
    uint32_t convertedValue = ntohl(networkValue);

    printf("Converted Value: %08x\n", convertedValue);

    return 0;
}

在这个例子中,我们演示了将主机字节序转换为网络字节序和将网络字节序转换为主机字节序的过程。这里使用的是32位整数,但对于16位短整数,可以使用 htonsntohs 来进行转换。

unsetunset6、tcp通信时send和recvunsetunset

在TCP通信中,sendrecv 函数通常不需要手动进行字节序的转换。这是因为TCP协议本身并不关心数据的表示形式,它仅仅负责按照字节流的形式传输数据。TCP是面向字节流的协议,它不关心数据的具体结构,也不对数据进行解释或处理。

字节序的问题通常涉及到在不同体系结构的计算机之间传输数据时,确保数据的正确解释。TCP通信在传输数据时会将数据以字节流的形式传输,而不关心数据的具体结构,因此不需要在sendrecv中进行字节序的转换。

字节序的问题更常见于那些有特定数据结构的通信协议或文件格式,例如网络协议头部、数据包格式、文件格式等。在这些情况下,确保发送端和接收端对数据的解释是一致的,就需要进行字节序的转换。

在实际的网络通信中,确保发送和接收端采用相同的字节序是非常重要的,但这通常是由高层协议或应用程序负责的,而不是由TCP协议本身负责。常用的解决方案是使用网络字节序(大端字节序)进行数据传输,并在需要的时候进行字节序的转换,以确保不同平台之间的数据一致性。

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

本文分享自 Linux兵工厂 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • unsetunset1、什么是字节序unsetunset
    • 字节序分类
      • 名字由来
      • unsetunset2、字节序优缺点unsetunset
        • 优缺点
          • 大端字节序
          • 小端字节序
        • 选择标准
        • unsetunset3、常见系统字节序unsetunset
          • 操作系统
            • 芯片架构
            • unsetunset4、系统字节序判断unsetunset
            • unsetunset5、网络字节序unsetunset
              • 特点和标准
                • 字节序转换
                  • 示例:
                  • unsetunset6、tcp通信时send和recvunsetunset
                  相关产品与服务
                  对象存储
                  对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档