C语言大小端字节序存储模式深入解读

C语言大小端字节序存储模式深入解读

介绍

在计算机存储体系中,一个数据在内存中是以若干字节为单位连续存储的。对于多字节数据的存储顺序,有两种规定:大端序和小端序,又分别称为网络字节序和主机字节序。C语言内存系统的存储方式是与它所运行的机器硬件有关的。在探讨之前,首先对大小端进行简单的介绍。

机器内存中的数据,大端和小端这两种存储方式主要考虑的是字节序。在计算机中,一个整型数字在内存中所占的大小是4个字节,这个4字节中并不是按照这个数据的本意进行存储的,而是分成了4个字节连续存储到内存中。

  • 大端序:将高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。例如数字 0x12345678 在内存中的表示形式是 12 34 56 78
  • 小端序:将低位字节存放在内存的低地址端,高位字节存放在内存的高地址端。例如数字 0x12345678 在内存中的表示形式是 78 56 34 12

C语言中的字节序函数

C语言中提供了函数 htonl()ntohl() 来实现大端字节序与小端字节序转化。字母 h 表示主机(Host),n 表示网络(Network),l 表示 32 位字长(long)。这两个函数主要用于将本地字节序转化成网络字节序:

uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);
  • htonl() 函数将 4 字节(32 位)的本机无符号整数转换为网络字节序无符号整数;
  • ntohl() 函数将 4 字节的网络字节序无符号整数转换为本机字节序的无符号整数。

因此,我们在网络通信中经常会用到这两个函数。

示例1

以十进制整数 16909060 (二进制表示为 00000001 00000010 00000011 00000100) 为例,分别以大小端字节序存储。

当以大端模式存储时,每一位的存储是这样的:

低地址 0x04 0x03 0x02 0x01 高地址
00000001 00000010 00000011 00000100

当以小端模式存储时,每位的存储是这样的:

低地址 0x01 0x02 0x03 0x04 高地址
00000001 00000010 00000011 00000100

示例2

在网络通信中,大端序是常用的网络字节序。下面介绍一个常见的网络通信的示例,计算机通过 socket 发送一个二进制数据包。下面分别以大端序和小端序来表示这个二进制数据包的字节序。

大端序

以一个 4 字节的数据 0x12345678 为例,其大端序的存储方式为 12 34 56 78,因此在向网络传输时,需要先将主机字节序转化为大端字节序,再进行网络通信。

#include <stdio.h>
#include <netinet/in.h>

int main() {
    uint32_t num = 0x12345678;
    uint32_t net = htonl(num); // 转换成大端序
    // 发送数据,注意这里使用的是大端序
    send(sock, &net, sizeof(net), 0);
    return 0;
}

小端序

如果采用小端序来实现网络通信的话,需要将主机字节序转化为小端字节序,并发送小端序的数据。

#include <stdio.h>
#include <netinet/in.h>

int main() {
    uint32_t num = 0x12345678;
    // 使用小端序
    uint32_t net = (num >> 24) | ((num << 8) & 0x00FF0000) | ((num >> 8) & 0x0000FF00) | (num << 24);
    // 发送数据,这里使用的是小端序
    send(sock, &net, sizeof(net), 0);
    return 0;
}

需要注意的是,在网络通信中,服务器和客户端要保证使用同一种字节序。如果一个是大端字节序,一个是小端字节序,就会发生数据解析错误。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言大小端字节序存储模式深入解读 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • c++实现发送http请求通过get方式获取网页源代码

    首先,C++实现发送HTTP请求需要使用到第三方库,最常用的是libcurl库。下面我们将具体介绍如何使用libcurl库来通过GET方式获取网页源代码。 步骤一:安装libcurl 根据自己的系统选择合适的安装方式,例如使用Linux系统下的包管理工具可以执行以下命令来安装: sudo apt-get install libcurl4-openssl-de…

    C 2023年5月24日
    00
  • 荣耀畅玩7c怎么开启热点?荣耀畅玩7c开启热点教程

    下面给您详细讲解荣耀畅玩7c如何开启热点的完整攻略: 一、前置条件 在进行热点开启之前,请确保您的荣耀畅玩7c已经连接到移动网络,并且您已经知道热点开启会消耗您的移动网络流量。 二、开启热点 从荣耀畅玩7c的系统设置进入到 “更多连接方式” 页面。 在更多连接方式页面中,点击 “个人热点”。如果您没有在荣耀畅玩7c上设置过热点,第一次点击个人热点会提示您开启…

    C 2023年5月23日
    00
  • jQuery深拷贝Json对象简单示例

    当我们需要复制一个json对象时,直接使用=赋值是不行的,因为这会导致两个变量指向同一个内存地址,修改其中一个对象的值会同时修改另一个对象的值。这时候我们需要使用深拷贝来复制json对象,这样两个对象就指向不同的内存地址,不会相互影响。 以下是深拷贝Json对象的示例代码: // 定义json对象 var obj1 = {"name":&…

    C 2023年5月23日
    00
  • js中如何获取JSON数组的长度

    获取JSON数组长度的方法有两种,分别是通过数组的length属性和通过Object的keys方法获取数组的长度。 通过数组的length属性获取长度: JSON数组即JavaScript中的数组,可以使用JavaScript的数组方法来获取数组长度,其中最常见的方法是使用length属性。 示例1: 假设现在有一个JSON数组,里面存储了一些数据: var…

    C 2023年5月23日
    00
  • C++ TCP网络编程详细讲解

    C++ TCP网络编程详细讲解 简介 TCP网络编程是指基于传输控制协议(TCP)实现的网络通信,其主要特点是数据传输稳定可靠,适用于对数据传输要求较高的应用场景。在C++中,我们可以使用一些网络编程库(如Boost.Asio、Winsock等)来实现TCP网络编程。 步骤 1. 创建socket 在进行TCP网络编程时,我们需要先创建一个socket,通过…

    C 2023年5月24日
    00
  • C++超详细讲解引用和指针

    C++超详细讲解引用和指针 什么是指针和引用 在C++中,指针和引用是两种重要的数据类型。 指针是一个变量,存储一块内存的地址;而引用则是一种别名,可以让我们通过一个名称来访问另一个变量或对象。 指针的声明和使用 指针的声明需要指定指针所指向的类型,并使用星号(*)进行标识。例如,声明一个指向整数类型的指针如下: int* ptr; 指针的使用需要注意以下几…

    C 2023年5月22日
    00
  • 避免elif和ELSE IF的阶梯和阶梯问题

    避免使用过多的elif和elseif语句是一个组织代码的好习惯,因为它们会导致代码不易维护,出现错误的可能性也更大。以下是一些关于如何避免elif和elseif语句阶梯和阶梯问题的建议: 使用字典代替elif语句 如果有一系列的if…elif语句,每个分支中的代码差别较小,这可以使用字典代替。 例如,我们想根据性别来获取某人的称呼: def get_ti…

    C 2023年5月9日
    00
  • c/c++获取系统时间函数的方法示例

    获取系统时间是编程中常用的功能之一,c/c++提供了多种方法来获取系统时间。下面将介绍获取系统时间的常用方法。 获取系统时间的常用函数 1. time() time()函数返回从1970年1月1日0时0分0秒到当前时间的秒数。time函数的详细定义如下: #include <time.h> time_t time(time_t *timer); …

    C 2023年5月30日
    00
合作推广
合作推广
分享本页
返回顶部