大小端模式转换

嗨喽,大家好,我是程序猿老王,程序老王就是我。

今天给大家讲一讲工作中经常遇到的大小端模式转换问题。

首先先来了解一下为什么会存在大小端模式转换

是因为在计算机中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8 bit。但是在C 语言中除了 8 bit 的char之外,还有 16 bit 的 short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型 x ,在内存中的地址为 0x0010,x 的值为0x1122,那么0x11位高字节,0x22位低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。

  • 大小端定义

不同机器内部对变量的字节存储顺序不同,有的采用大端模式(big-endian),有的采用小端模式(little-endian)。

大端模式是指高字节数据存放在低地址处,低字节数据放在高地址处。

小端模式是指低字节数据存放在低地址处,高字节数据放在高地址处。

下面给大家看一个示例就知道了什么是大小端了:

0x12345678在小端模式内存中的表示形式:


 内存 低地址 -----------------> 高地址
       0x78 | 0x56 | 0x34 | 0x12 
     低字节 -----------------> 高字节

0x12345678在大端模式内存中的表示形式:

 内存 低地址 -----------------> 高地址
     0x12 | 0x34 | 0x56 | 0x78
     高字节 -----------------> 低字节
  • 大小端模式转换方法

在网络上传输数据时,由于数据传输的两端可能对应不同的硬件平台,采用的存储字节顺序也可能不一致,因此 TCP/IP 协议规定了在网络上必须采用网络字节顺序(也就是大端模式) 。

通过对大小端的存储原理分析可发现,对于 char 型数据,由于其只占一个字节,所以不存在这个问题,这也是一般情况下把数据缓冲区定义成 char 类型 的原因之一。对于 IP 地址、端口号等非 char 型数据,必须在数据发送到网络上之前将其转换成大端模式,在接收到数据之后再将其转换成符合接收端主机的存储模式

Linux 系统为大小端模式的转换提供了 4 个函数,函数原型:


#include <arpa/inet.h> 
 
uint32_t htonl(uint32_t hostlong); 
uint16_t htons(uint16_t hostshort); 
uint32_t ntohl(uint32_t netlong); 
uint16_t ntohs(uint16_t netshort);

htonl 表示 host to network long,用于将主机 unsigned int 型数据转换成网络字节顺序; 
htons 表示 host to network short,用于将主机 unsigned short 型数据转换成网络字节顺序; 
ntohl、ntohs 的功能分别与 htonl、htons 相反。
  • 最后再给大家展示一下模拟实现大小端转换函数


typedef unsigned short int uint16;
typedef unsigned long int uint32;
 
/*短整型大小端互换*/
#define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | \
                            (((uint16)(A) & 0x00ff) << 8))
/*长整型大小端互换*/
#define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | \
                            (((uint32)(A) & 0x00ff0000) >> 8) | \
                            (((uint32)(A) & 0x0000ff00) << 8) | \
                            (((uint32)(A) & 0x000000ff) << 24))

/*本机大端返回1,小端返回0*/
int checkCPUendian(void)
{
   union{
      unsigned long int i;
      unsigned char s[4];
   }c;

   c.i = 0x12345678;
   return (0x12 == c.s[0]);
}
 
/*模拟htonl函数,本机字节序转网络字节序*/
unsigned long int t_htonl(unsigned long int h)
{
       /*若本机为大端,与网络字节序同,直接返回*/
       /*若本机为小端,转换成大端再返回*/
       return checkCPUendian() ? h : BigLittleSwap32(h);
}
 
/*模拟ntohl函数,网络字节序转本机字节序*/
unsigned long int t_ntohl(unsigned long int n)
{
       /*若本机为大端,与网络字节序同,直接返回*/
       /*若本机为小端,网络数据转换成小端再返回*/
       return checkCPUendian() ? n : BigLittleSwap32(n);
}
 
/*模拟htons函数,本机字节序转网络字节序*/
unsigned short int t_htons(unsigned short int h)
{
       /*若本机为大端,与网络字节序同,直接返回*/
       /*若本机为小端,转换成大端再返回*/
       return checkCPUendian() ? h : BigLittleSwap16(h);
}
 
/*模拟ntohs函数,网络字节序转本机字节序*/
unsigned short int t_ntohs(unsigned short int n)
{
       /*若本机为大端,与网络字节序同,直接返回*/
       /*若本机为小端,网络数据转换成小端再返回*/
       return checkCPUendian() ? n : BigLittleSwap16(n);
}

-END-


关于更多嵌入式C语言、FreeRTOS、RT-Thread、Linux应用编程、linux驱动等相关知识,关注公众号【嵌入式Linux知识共享】,后续精彩内容及时收看了解。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,大小端数据转换是指将一个字节序列从一种字节顺序(大小端转换为另一种字节顺序的过程。在计算机中,数据的存储方式可以是大端模式(Big-Endian)或小端模式(Little-Endian)。 在大端模式中,高位字节存储在低地址,低位字节存储在高地址;而在小端模式中,高位字节存储在高地址,低位字节存储在低地址。 下面是一个示例代码,用于将大小端数据进行转换: ```c #include <stdio.h> // 判断当前系统的字节序 int isLittleEndian() { int num = 1; // 将int类型的指针强制转换为char类型的指针 char *p = (char *)&num; // 如果低地址存放的是最低有效字节,则为小端模式 if (*p == 1) { return 1; } return 0; } // 大小端数据转换 unsigned int endianConversion(unsigned int num) { unsigned int result = 0; unsigned char *p1, *p2; p1 = (unsigned char *)&num; p2 = (unsigned char *)&result; if (isLittleEndian()) { // 小端模式转换为大端模式 p2 = p1; p2 = p1; p2 = p1; p2 = p1; } else { // 大端模式转换为小端模式 p2 = p1; p2 = p1; p2 = p1; p2 = p1; } return result; } int main() { unsigned int num = 0x12345678; unsigned int convertedNum = endianConversion(num); printf("原始数据:0x%08X\n", num); printf("转换后的数据:0x%08X\n", convertedNum); return 0; } ``` 上述代码中,`isLittleEndian()`函数用于判断当前系统的字节序,返回1表示小端模式,返回0表示大端模式。`endianConversion()`函数用于进行大小端数据的转换,根据当前系统的字节序进行相应的转换操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值