`

long long 类型的网络字节顺序转换

阅读更多

long long 类型的网络字节顺序转换

sailor_forever sailing_9806@163.com 转载请注明

http://blog.csdn.net/sailor_8318/archive/2007/08/04/1726064.aspx

 

 

做过socket的都知道网络字节转换的事情,网络中传输的数据是纯字节流,没有类型信息,从低地址开始传递;网络字节序通常为大端的,即先传递高字节,因此和大端的本地字节存储顺序一致,和小端的则截然相反。为了数据的一致性,就要把本地的数据转换成网络上使用的格式,然后发送出去,接收的时候也是一样的,经过转换然后才去使用这些数据。基本的库函数中提供了这样的可以进行字节转换的函数,如和htons( ) htonl( ) ntohs( ) ntohl( ),这里n表示networkh表示hosthtons( ) htonl( )用于本地字节向网络字节转换的场合,s表示short,即对2字节操作,l表示long即对4字节操作。同样ntohs( )ntohl( )用于网络字节向本地格式转换的场合。随着c99标准的推行,我们伟大的c中增加了新的类型long long int unsigned long long int,都是64位的,怎么办?不转肯定是不行,就得自己想办法把它转了。当然有很多方法,我这里想使用一种类比的解决方法,看看如何举一反三。

 

一、字节序定义

字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序。其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。一次Sun SPARCIntel X86的平台移植让我们的程序遭遇了“字节序问题”。

 

在所有的介绍字节序的文章中都会提到字节序分为两类:Big-EndianLittle-Endian。引用标准的Big-EndianLittle-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

 

二、高/低地址与高低字节

首先我们要知道我们C程序映像中内存的空间布局情况:在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明,大致如下图:

----------------------- 最高内存地址 0xffffffff

。。。。。。

 栈底

 .

 .                       

  栈顶

-----------------------

 |

 |

NULL (空洞)

/|\

-----------------------

                          

-----------------------

未初始化的数据

----------------------         (统称数据段)

初始化的数据

-----------------------

正文段(代码段)

----------------------- 最低内存地址 0x00000000

以上图为例如果我们在栈上分配一个unsigned char buf[4],那么这个数组变量在栈上是如何布局的呢?看下图:

栈底 (高地址)

----------

buf[3]

buf[2]

buf[1]

buf[0]

----------

栈顶 (低地址)

 

现在我们弄清了高低地址,接着我来弄清高/低字节,如果我们有一个32位无符号整型0x12345678(呵呵,恰好是把上面的那4个字节buf看成一个整型),那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿0x12345678来说,从高位到低位的字节依次是0x120x340x560x78

高低地址和高低字节都弄清了。我们再来回顾一下Big-EndianLittle-Endian的定义,并用图示说明两种字节序:

unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value

Big-Endian: 低地址存放高位,如下图:

栈底 (高地址)

---------------

buf[3] (0x78) -- 低位

buf[2] (0x56)

buf[1] (0x34)

buf[0] (0x12) -- 高位

---------------

栈顶 (低地址)

Little-Endian: 低地址存放低位,如下图:

栈底 (高地址)

---------------

buf[3] (0x12) -- 高位

buf[2] (0x34)

buf[1] (0x56)

buf[0] (0x78) -- 低位

---------------

栈顶 (低地址)

 

在现有的平台上IntelX86采用的是Little-Endian,而像SunSPARC采用的就是Big-Endian

 

三、网络字节序的转换

假设对于little endianIA-32架构上面的Linux,首先考虑网络字节转换的结果与原来有什么不同,如 int a = 0x12345678b = htnla),那么就应该是0x78563412。如果是 short c = 0x1234short d = 0x5678e = htons(c)f = htons(d),这样e=0x3412f=0x7856如果能把ef调换一下组合放在一起,不就是一个整型aa=0x12345678)转换之后的值么?实验的代码如下:

#include <stdio.h>

struct ST{

    short val1;

    short val2;

};

union U{

    int val;

    struct ST st;

};

 

int main(void)

{

    int a = 0;

    union U u1, u2;

 

    a = 0x12345678;

    u1.val = a;

    printf("u1.val is 0x%x\n", u1.val);

    printf("val1 is 0x%x\n", u1.st.val1);

    printf("val2 is 0x%x\n", u1.st.val2);

    printf("after first convert is: 0x%x\n", htonl(u1.val));

    u2.st.val2 = htons(u1.st.val1);

    u2.st.val1 = htons(u1.st.val2);

    printf("after second convert is: 0x%x\n", u2.val);

    return 0;

}

输出结果:

u1.val is 0x12345678

val1 is 0x5678

val2 is 0x1234

after first convert is: 0x78563412

after second convert is: 0x78563412

 

按照这种想法我们实现long long int64bit 类型,把它分割成两个int32bit),然后分别使用htonl(),分别转换,然后再将两种int交换顺序重新组合,即实现了整个64位的八个字节的翻转。

代码如下:

#include <stdio.h>

struct ST{

    int val1;

    int val2;

};

union test {

    long long int val;

    struct ST st;

};

 

int main(void)

{

    long long int a;

    union test u1, u2;

 

    a = 0x7654321087654321LL;

    u1.val = a;

    u2.st.val2 = htonl(u1.st.val1);

    u2.st.val1 = htonl(u1.st.val2);

    printf("val1 is 0x%x\n", u2.st.val1);

    printf("val2 is 0x%x\n", u2.st.val2);

    printf("u1.val     is    : 0x%llx\n", u1.val);

    printf("after convert is : 0x%llx\n", u2.val);

   

    return 0;

}

执行结果:

val1 is 0x10325476

val2 is 0x21436587

u1.val     is    : 0x7654321087654321

after convert is  : 0x2143658710325476

 

另外注意long long int 最大值是0x7fffffffffffffff,即7后面15f263次方减1 unsigned long long int 最大值是0xffffffffffffffff16f(264次方减1)。程序中long long int 可以简写为 long long,但是记住这是简写,就像longlong int的简写。

 

想看数据在内存中如何存储的,就用gdb吧!使用gdb x命令,如 x /xb &a表示要察看存储在变量a中的前一个字节(byte)中的数据(16进制)。x /xw &a 就是要察看变量a中前4个字节(word)数据(16进制)。x /xg &a 察看a开始8个字节的数据。

分享到:
评论

相关推荐

    LongInt Float Double与字节数组的转换.rar

    反向操作,即从字节数组恢复`LongInt`,则需要按照字节顺序重新组合这4个字节,再解析为整数。 其次,`Float`是单精度浮点数,它在内存中占据4个字节,包含一个符号位、8位指数和23位小数部分。转换`Float`到字节...

    络字节序、地址转换源代码

    在计算机网络中,数据传输涉及一个关键的概念:字节序,即字节在网络中的顺序。字节序分为两种类型:大端字节序(Big-Endian)和小端字节序(Little-Endian)。理解这两种字节序对于进行跨平台的网络通信至关重要,...

    ntohs, ntohl, htons,htonl的比较和详解.pdf

    这些函数可以将主机字节顺序转换为网络字节顺序,或者将网络字节顺序转换为主机字节顺序。 htonl() 函数将主机的无符号长整形数转换成网络字节顺序。ntohl() 函数将一个无符号长整形数从网络字节顺序转换为主机字节...

    网络字节序和主机字节序

    这些函数可以将Unsigned Short 和 Unsigned Long 类型的数据从主机序转换到网络序或从网络序转换到主机序。 在使用 Little Endian 的系统中,这些函数会把字节序进行转换,而在使用 Big Endian 的系统中,这些函数...

    5_网络字节序_werevj4_

    在跨平台的网络编程中,字节序转换函数如htonl(主机到网络字节序,long)、ntohl(网络到主机字节序,long)、htons(主机到网络字节序,short)和ntohs(网络到主机字节序,short)非常常见,它们确保数据在网络上...

    socket总结资料(Linux)

    - `htonl()`:将主机字节顺序的long整数转换为网络字节顺序。 - `ntohs()`:将网络字节顺序的short整数转换为主机字节顺序。 - `ntohl()`:将网络字节顺序的long整数转换为主机字节顺序。 五、IP地址转换函数 1...

    Host-byte-order-to-network-.rar_byte order_doc

    例如,`htons()`、`htonl()`、`ntohs()` 和 `ntohl()` 分别用于将短整型(short)、无符号短整型(unsigned short)、长整型(long)和无符号长整型(unsigned long)从主机字节顺序转换为网络字节顺序,以及反向...

    高低字节交换SWAP演示.rar

    高低字节交换(Byte Swapping),又称为字节翻转,是一种处理字节顺序的技术,主要用于解决大端字节序和小端字节序之间的转换问题。大端字节序是指数据的最高有效字节存储在最低地址,而小端字节序则相反,最低有效...

    ip2long和long2ip的学习程序

    这个数字是由IPv4的四个八位字节按照从左到右的顺序转换得到的,每个字节被转换为十进制表示,并用点号分隔。这个转换过程称为“点分十进制”到“网络字节序”的转换。 转换过程如下: 1. 将 "192" 转换为十进制 ...

    数组的转换函数

    在Java中,这种转换尤为常见,特别是涉及到网络字节序时,因为网络字节序是TCP/IP协议栈规定的标准字节顺序,通常为大端字节序(Big-Endian)。 上述代码片段提供了一些在Java中实现整型数(long类型)与网络字节序...

    数据类型转换程序,输入输出支持大小端序

    2. **字节序**:计算机存储数据时,多字节类型(如整数、浮点数)的字节顺序有两种主要方式,即大端序(Big-Endian)和小端序(Little-Endian)。大端序是指最高位的字节存储在内存地址的低位,而小端序则相反,最低...

    Cnic.Convert.rar_byte_数据类型转换

    - 将`byte[]`转换回`int`或`Long`,需要按照正确的顺序组合字节,可能还需要考虑字节序(Big-Endian或Little-Endian)。 - 使用位移操作将每个字节的值移到适当位置,然后通过逻辑或运算(`|`)组合成原始数值。 ...

    Linux网络编程细节

    1. htonl():这是Host to Network Long的缩写,用于将主机上的32位无符号整数(long)转换为网络字节顺序。在Windows中,它包含在头文件中;而在Linux中,它位于头文件中。例如,在发送一个结构体如`STU`时,其中的...

    java基本类型与byte数组互相转换.rar

    - **Int到Byte Array**:使用`ByteBuffer`类,它可以以字节顺序存储各种基本类型的数据。通过`ByteBuffer.allocate()`分配空间,然后调用`putInt()`将整数写入缓冲区,最后调用`array()`获取字节数组。 - **Float ...

    Java与其他语言数据类型之间的转换方法

    因此,当Java程序与非Java环境进行通信时,需要对字节顺序进行转换,以确保数据的一致性。 在提供的代码段中,我们可以看到几个关键的方法,用于在Java中进行字节序转换: 1. `toLH(int n)` 和 `toHH(int n)`:这...

    JAVA转byte[]为int,long,double

    因此,从`byte[]`转换到`int`,我们需要确保数组长度至少为4,并按照字节顺序(通常为大端或小端)正确组合字节。这里我们假设默认的大端序: ```java public static int bytesToInt(byte[] bytes) { return ...

    Java整型数与网络字节序byte[]数组转换关系详解

    Java中的整型数包括int、long、short等类型,而网络字节序是指在网络传输中的字节顺序。由于Java和C/C++之间的数据类型长度不一致,因此需要进行相应的转换。 在Java中,将整型数转换为byte[]数组可以使用位操作符...

    linux网络编程[收集].pdf

    总的来说,Linux网络编程涉及的知识点广泛,包括网络字节序的转换、socket地址结构体、地址类型识别、以及IP地址的字符串和二进制表示之间的转换。熟练掌握这些基本概念和函数使用是编写高效、可移植的网络程序的...

    浮点数、Double与字节数组互转,C/C++函数

    可以使用`htonl`(主机到网络,long类型)、`htons`(主机到网络,short类型)、`ntohl`和`ntohs`(网络到主机)函数处理字节序,但这些函数只适用于整数类型。对于浮点数和Double,可以编写自定义函数来实现字节序...

    分解长整型数据 读取每一个字节的内容

    理解字节顺序和数据类型在解码过程中的作用是至关重要的,否则可能会导致数据解析错误。 6. 应用场景: - 数据传输:在发送或接收二进制数据时,需要将长整型数据分解成字节序列进行传输。 - 存储优化:在内存...

Global site tag (gtag.js) - Google Analytics