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语言大小端格式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于"引用"的几点说明介绍

    关于"引用"的几点说明介绍

    引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名
    2013-09-09
  • C++之BOOST字符串查找示例

    C++之BOOST字符串查找示例

    这篇文章主要介绍了C++之BOOST字符串查找的方法,实例演示了boost针对字符串的查找、判定及替换等操作,具有一定的实用价值,需要的朋友可以参考下
    2014-10-10
  • C++类和对象之相关特性解读

    C++类和对象之相关特性解读

    这篇文章主要介绍了C++类和对象之相关特性,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • C++实现连连看游戏核心代码

    C++实现连连看游戏核心代码

    这篇文章主要为大家详细介绍了C++实现连连看游戏核心代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 手拉手教你如何理解c/c++中的指针

    手拉手教你如何理解c/c++中的指针

    当你对C越来越熟悉时,你会发现把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一,这篇文章主要给大家介绍了关于c/c++中指针的相关资料,需要的朋友可以参考下
    2021-10-10
  • C++实现大数相乘的算法

    C++实现大数相乘的算法

    这篇文章主要为大家详细介绍了C++实现大数相乘的算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • C++内存四区模型使用及说明

    C++内存四区模型使用及说明

    C++内存分为代码区(只读共享)、全局区(存全局/静态变量及常量)、栈区(自动管理,存函数参数和局部变量)、堆区(手动管理,用new分配,delete释放),各区域数据生命周期不同,提供灵活编程
    2025-09-09
  • C++常量详解二(常量形参,常量返回值,常量成员函数)

    C++常量详解二(常量形参,常量返回值,常量成员函数)

    这篇文章主要介绍了C++常量详解二(常量形参,常量返回值,常量成员函数),需要的朋友可以参考下
    2017-06-06
  • C++实现LeetCode(166.分数转循环小数)

    C++实现LeetCode(166.分数转循环小数)

    这篇文章主要介绍了C++实现LeetCode(166.分数转循环小数)
    2021-07-07
  • C++中构造函数的参数缺省的详解

    C++中构造函数的参数缺省的详解

    这篇文章主要介绍了C++中构造函数的参数缺省的详解的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-10-10

最新评论