C语言大小端格式详解

C语言大小端格式详解

🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习

🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发

❄️作者主页:一个平凡而乐于分享的小比特的个人主页

✨收录专栏:c语言重要知识点总结,本专栏旨在总结C语言学习过程中的易错点,通过调试代码,分析原理,对重要知识点有更清晰的理解

欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

一、什么是大小端格式

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

1. 小端格式 (Little Endian)

  • 低字节 存放在低地址
  • 高字节存放在高地址
  • 像Intel x86/x64、ARM(默认)使用小端
c 复制代码
#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;
}

在小端机器上输出:

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

2. 大端格式 (Big Endian)

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

二、如何检测大小端

方法1:使用联合体

c 复制代码
#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:使用指针

c 复制代码
int isLittleEndian() {
    int num = 1;
    return *(char *)&num == 1;
}

三、字节序转换函数

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

c 复制代码
#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:网络数据包解析

c 复制代码
#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:文件格式处理

c 复制代码
// 读取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等)
c 复制代码
// 安全的字节序无关的读取
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
  • 大端:高字节在低地址,用于网络和某些硬件
  • 网络通信必须使用大端
  • 本地存储通常使用本机字节序
  • 跨平台开发要注意字节序转换

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

相关推荐
码农小韩16 分钟前
基于Linux的C++学习——循环
linux·c语言·开发语言·c++·算法
Q741_14734 分钟前
海致星图招聘 数据库内核研发实习生 一轮笔试 总结复盘(2) 作答语言:C/C++ 哈夫曼编码 LRU
c语言·数据库·c++·算法·笔试·哈夫曼编码·哈夫曼树
你怎么知道我是队长36 分钟前
C语言---位域
c语言·开发语言
爱吃生蚝的于勒3 小时前
【Linux】进程间通信之匿名管道
linux·运维·服务器·c语言·数据结构·c++·vim
!停3 小时前
C语言单链表
c语言·数据结构·算法
南行*3 小时前
C语言Linux环境编程
linux·c语言·开发语言·网络安全
你怎么知道我是队长4 小时前
C语言---printf函数使用详细说明
c语言·开发语言
消失的旧时光-19434 小时前
函数指针 + 结构体 = C 语言的“对象模型”?——从 C 到 C++ / Java 的本质统一
linux·c语言·开发语言·c++·c
代码游侠4 小时前
学习笔记——ESP8266 WiFi模块
服务器·c语言·开发语言·数据结构·算法
Felven16 小时前
A. Helmets in Night Light
c语言