long, double类型的大小端处理

来源:互联网 发布:网络的安全 编辑:程序博客网 时间:2024/06/05 18:14


首先简要说明一下数据大小端模式。

大端模式

所谓的大端模式(Big-endian)指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式

所谓的小端模式(Little-endian),指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

 

内存中存储的区别:

以32bit的int型数据0x11223344为例,来说明大小端的区别:

 

大端

11

22

33

44

小端

44

33

22

11

内存地址

0x0000

0x0001

0x0002

0x0003

 

可见大小端只是针对16bit,32bit,64bit这些占用多于一个字节的数据类型,字节流不存在大小端问题。

大小端的使用情况

目前Intel的x86系列芯片是唯一还在坚持使用小端的芯片,ARM芯片默认采用小端,但可以切换为大端;而MIPS等芯片要么采用全部大端的方式储存,要么提供选项支持大端——可以在大小端之间切换。另外,对于大小端的处理也和编译器的实现有关,Java是平台无关的,默认是大端。在网络上传输数据普遍采用的都是大端模式。

 

可以看出,大小端只是在不同平台间进行数据交换是时候有用。如果在同一个平台下,不管数据在内存中实际是如何表示的,不会影响程序对数据的解释,也就是不用考虑大小端的问题。只有在网络传输时,因为会涉及到不同的平台,才需要考虑大小端的问题。一般情况下,网络上传输数据采用的都是大端模式,如不考虑大小端模式,有可能把一个整型的0x1234做为0x3412处理,导致程序异常。因此,在网络编程时就引入了主机字节序和网络字节序相互转换的函数。

系统字节序转换函数

系统标准定义的转换函数有4个:

      htonl()--"Hostto Network Long int"     32bit

      ntohl()--"Networkto Host Long int"     32 bit

      htons()--"Hostto Network Short int"   16 bit

      ntohs()--"Networkto Host Short int"   16 bit

 

在Linux系统下的头文件及函数定义:

  #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);

 

在Windows系统的头文件及函数定义:

        #include<Winsock2.h>

       u_short PASCAL FAR ntohs( u_short netshort);

       u_long PASCAL FAR ntohl( u_long netlong);

       u_short PASCAL FAR htons( u_short hostshort);

       u_long PASCAL FAR htonl( u_long hostlong);

 

 

扩展的64bit long类型的大小端转换函数


static inline int isBigEndian(void) //测试主机大小端

{

   union {

       int32_t i;

       char c[4];

    }u;

   u.i = 1;

   return (u.c[0] == 0);

}

 

#define swab64(x) \

                   ((uint64_t)(\

                                     (((uint64_t)(x)& (uint64_t)0x00000000000000ffULL) << 56) | \

                                     (((uint64_t)(x)& (uint64_t)0x000000000000ff00ULL) << 40) | \

                                     (((uint64_t)(x)& (uint64_t)0x0000000000ff0000ULL) << 24) | \

                                     (((uint64_t)(x)& (uint64_t)0x00000000ff000000ULL) << 8) | \

                                     (((uint64_t)(x)& (uint64_t)0x000000ff00000000ULL) >> 8) | \

                                     (((uint64_t)(x)& (uint64_t)0x0000ff0000000000ULL) >> 24) | \

                                     (((uint64_t)(x)& (uint64_t)0x00ff000000000000ULL) >> 40) | \

                                     (((uint64_t)(x)& (uint64_t)0xff00000000000000ULL) >> 56) ))

 

uint64_t htonll(uint64_t x)

{

   if (isBigEndian()) {

       return x;

    }else {

       return swab64(x);

    }

   

}

 

uint64_t ntohll(uint64_t x)

{

   return htonll(x);

}

 

对float类型的转换

系统函数和扩展的函数都是针对整型的数据类型。对于浮点数,如果也想使用这些函数,需要做些额外的工作。下面以64bit的double类型为例,来说明使用方法。

 

       doubleinputData64;

       假设inputData64是从网络端获取的double类型的数据,下面的代码把正确字节序的double类型的数据保存在data64中。

       uint8_t * pData  = (uint8_t *) & inputData64;

       uint64_t tmp_64;

       doubledata64;

       tmp_64 = ntohll(*((uint64_t *)pData));

       memcpy(&data64, &tmp_64, sizeof (uint64_t));

阅读全文
0 0
原创粉丝点击