C语言大小端格式举例详解

 更新时间:2025年12月18日 10:18:15   作者:一个平凡而乐于分享的小比特  
大小端是嵌入式C语言中一个重要的概念,它涉及到多字节数据在内存中的存储顺序,下面这篇文章主要介绍了C语言大小端格式的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、什么是大小端格式

大小端指的是多字节数据在内存中的存储顺序。

1.小端格式 (Little Endian)

  • 低字节存放在低地址
  • 高字节存放在高地址
  • 像Intel x86/x64、ARM(默认)使用小端
#include <stdio.h>

int main() {
    int num = 0x12345678;  // 十六进制数
    unsigned char *p = (unsigned char *)#
    
    printf("值: 0x%x\n", num);
    printf("内存布局(低地址->高地址):\n");
    
    for(int i = 0; i < sizeof(int); i++) {
        printf("地址 %p: 0x%x\n", p+i, *(p+i));
    }
    
    return 0;
}

在小端机器上输出:

值: 0x12345678
内存布局(低地址->高地址):
地址 0x7ffe...: 0x78  // 最低字节
地址 0x7ffe...: 0x56
地址 0x7ffe...: 0x34
地址 0x7ffe...: 0x12  // 最高字节

2.大端格式 (Big Endian)

  • 高字节存放在低地址
  • 低字节存放在高地址
  • 像PowerPC、网络字节序使用大端
// 假设在大端机器上运行上述代码,输出为:
值: 0x12345678
内存布局(低地址->高地址):
地址 0x7ffe...: 0x12  // 最高字节
地址 0x7ffe...: 0x34
地址 0x7ffe...: 0x56
地址 0x7ffe...: 0x78  // 最低字节

二、如何检测大小端

方法1:使用联合体

#include <stdio.h>

union EndianTest {
    int i;
    char c[sizeof(int)];
};

int isLittleEndian() {
    union EndianTest test;
    test.i = 1;
    return test.c[0] == 1;  // 如果最低地址字节是1,则是小端
}

int main() {
    if (isLittleEndian()) {
        printf("这是小端机器\n");
    } else {
        printf("这是大端机器\n");
    }
    return 0;
}

方法2:使用指针

int isLittleEndian() {
    int num = 1;
    return *(char *)&num == 1;
}

三、字节序转换函数

网络编程中经常需要转换:

#include <arpa/inet.h>  // Linux
// 或 #include <winsock2.h>  // Windows

uint32_t htonl(uint32_t hostlong);   // 主机->网络(32位)
uint16_t htons(uint16_t hostshort);  // 主机->网络(16位)
uint32_t ntohl(uint32_t netlong);    // 网络->主机(32位)
uint16_t ntohs(uint16_t netshort);   // 网络->主机(16位)

// 示例:
uint32_t host_value = 0x12345678;
uint32_t network_value = htonl(host_value);  // 转换为网络字节序

四、什么情况下使用哪种格式

使用小端格式的情况:

  1. x86/x64架构的CPU(Intel、AMD)
  2. ARM处理器(默认小端,可切换)
  3. Windows/Linux桌面系统
  4. 多数嵌入式系统
  5. 本地数据存储(当不需要跨平台时)

优点:

  • 数学运算方便(从低字节开始处理)
  • 类型转换简单

使用大端格式的情况:

  1. 网络协议(TCP/IP规定使用大端)
  2. PowerPC架构
  3. 某些旧版SPARC、MIPS系统
  4. Java虚拟机内部(大端)
  5. 图像文件格式(如BMP、JPEG)
  6. 某些硬件设备的寄存器

优点:

  • 人类阅读友好(与书写顺序一致)
  • 容易判断数值正负(符号位在最低地址)

五、实际应用示例

示例1:网络数据包解析

#include <stdio.h>
#include <stdint.h>

// 模拟从网络接收的数据(大端格式)
void parseNetworkPacket(const uint8_t *packet) {
    // 前4字节是大端的IP地址
    uint32_t ip = (packet[0] << 24) | 
                  (packet[1] << 16) | 
                  (packet[2] << 8) | 
                  packet[3];
    
    // 使用ntohl转换成本机字节序
    ip = ntohl(*(uint32_t*)packet);  // 更标准的做法
    
    printf("IP地址: %u.%u.%u.%u\n", 
           (ip >> 24) & 0xFF,
           (ip >> 16) & 0xFF,
           (ip >> 8) & 0xFF,
           ip & 0xFF);
}

示例2:文件格式处理

// 读取BMP文件头(大端格式)
#pragma pack(push, 1)
typedef struct {
    uint16_t signature;     // "BM",大端
    uint32_t fileSize;      // 大端
    uint16_t reserved1;
    uint16_t reserved2;
    uint32_t dataOffset;    // 大端
} BMPHeader;
#pragma pack(pop)

void readBMP(const char *filename) {
    FILE *file = fopen(filename, "rb");
    BMPHeader header;
    fread(&header, sizeof(header), 1, file);
    
    // 转换字节序
    header.signature = ntohs(header.signature);
    header.fileSize = ntohl(header.fileSize);
    header.dataOffset = ntohl(header.dataOffset);
    
    fclose(file);
}

六、编写跨平台代码的建议

  1. 使用标准转换函数(htonl/ntohl等)
  2. 避免直接内存拷贝不同字节序的数据
  3. 明确数据格式在文档中说明
  4. 测试时考虑字节序
  5. 使用固定宽度整数类型(uint8_t, uint32_t等)
// 安全的字节序无关的读取
uint32_t readUint32BigEndian(const uint8_t *buffer) {
    return (buffer[0] << 24) | 
           (buffer[1] << 16) | 
           (buffer[2] << 8) | 
           buffer[3];
}

uint32_t readUint32LittleEndian(const uint8_t *buffer) {
    return buffer[0] | 
           (buffer[1] << 8) | 
           (buffer[2] << 16) | 
           (buffer[3] << 24);
}

总结

  • 小端:低字节在低地址,常见于Intel CPU
  • 大端:高字节在低地址,用于网络和某些硬件
  • 网络通信必须使用大端
  • 本地存储通常使用本机字节序
  • 跨平台开发要注意字节序转换

理解大小端对网络编程、文件格式解析、硬件交互等至关重要!

到此这篇关于C语言大小端格式的文章就介绍到这了,更多相关C语言大小端格式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++ 编程 几个有用的宏详解

    c++ 编程 几个有用的宏详解

    下面小编就为大家带来一篇c++ 编程 几个有用的宏详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • c++二叉树的几种遍历算法

    c++二叉树的几种遍历算法

    c++二叉树的几种遍历算法,需要的朋友可以参考一下
    2013-02-02
  • C++使用邮件槽实现ShellCode跨进程传输

    C++使用邮件槽实现ShellCode跨进程传输

    在计算机安全领域,进程间通信(IPC)一直是一个备受关注的话题,在本文中,我们将探讨如何使用Windows邮件槽(Mailslot)实现ShellCode的跨进程传输,需要的可以参考下
    2023-12-12
  • C++面试题之数a、b的值互换(不使用中间变量)

    C++面试题之数a、b的值互换(不使用中间变量)

    这篇文章主要介绍了不使用中间变量,C++实现数a、b的值互相转换操作,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Visual Studio Community 2022(VS2022)安装图文方法

    Visual Studio Community 2022(VS2022)安装图文方法

    这篇文章主要介绍了Visual Studio Community 2022(VS2022)安装方法,本文分步骤通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • C++深入详解单例模式与特殊类设计的实现

    C++深入详解单例模式与特殊类设计的实现

    这篇文章主要为大家详细介绍了C++单例模式和特殊类的设计,单例模式这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-06-06
  • 实现opencv图像裁剪分屏显示示例

    实现opencv图像裁剪分屏显示示例

    这篇文章主要介绍了实现opencv图像裁剪分屏显示示例,需要的朋友可以参考下
    2014-04-04
  • C++实现有向图的邻接表表示

    C++实现有向图的邻接表表示

    这篇文章主要为大家详细介绍了C++实现有向图的邻接表表示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C 语言实现一个简单的 web 服务器的原理解析

    C 语言实现一个简单的 web 服务器的原理解析

    这篇文章主要介绍了C 语言实现一个简单的 web 服务器的原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • C++实现动态数组功能

    C++实现动态数组功能

    这篇文章主要为大家详细介绍了C++实现动态数组功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11

最新评论