做过socket的都知道网络字节转换的事情,网络中传输的数据是纯字节流,没有类型信息,从低地址开始传递;网络字节序通常为大端的,即先传递高字节,因此和大端的本地字节存储顺序一致,和小端的则截然相反。为了数据的一致性,就要把本地的数据转换成网络上使用的格式,然后发送出去,接收的时候也是一样的,经过转换然后才去使用这些数据。基本的库函数中提供了这样的可以进行字节转换的函数,如和htons( ) htonl( ) ntohs( ) ntohl( ),这里n表示network,h表示host,htons( ) htonl( )用于本地字节向网络字节转换的场合,s表示short,即对2字节操作,l表示long即对4字节操作。同样ntohs( )ntohl( )用于网络字节向本地格式转换的场合。随着c99标准的推行,我们伟大的c中增加了新的类型long long int ,unsigned long long int,都是64位的,怎么办?不转肯定是不行,就得自己想办法把它转了。当然有很多方法,我这里想使用一种类比的解决方法,看看如何举一反三。
一、字节序定义
字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序。其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。一次Sun SPARC到Intel X86的平台移植让我们的程序遭遇了“字节序问题”。
在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-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来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。
高低地址和高低字节都弄清了。我们再来回顾一下Big-Endian和Little-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) -- 低位
---------------
栈顶 (低地址)
在现有的平台上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。
三、网络字节序的转换
假设对于little endian的IA-32架构上面的Linux,首先考虑网络字节转换的结果与原来有什么不同,如 int a = 0x12345678,b = htonl(a),那么就应该是0x78563412。如果是 short c = 0x1234,short d = 0x5678,e = htons(c),f = htons(d),这样e=0x3412,f=0x7856,如果能把e和f调换一下组合放在一起,不就是一个整型a(a=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 int(64bit)类型,把它分割成两个int(32bit),然后分别使用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后面15个f(2的63次方减1) unsigned long long int 最大值是0xffffffffffffffff,16个f(2的64次方减1)。程序中long long int 可以简写为 long long,但是记住这是简写,就像long是long int的简写。
想看数据在内存中如何存储的,就用gdb吧!使用gdb中 x命令,如 x /xb &a表示要察看存储在变量a中的前一个字节(byte)中的数据(16进制)。x /xw &a 就是要察看变量a中前4个字节(word)数据(16进制)。x /xg &a 察看a开始8个字节的数据。
网络字节转换行数如果是win32则定义在winsock2.h内,否则,定义在netdb.h sys/socket.h netinet/in.h等3个头文件中
#ifdef __WIN32__
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ljlsunny/archive/2009/09/07/4526770.aspx
分享到:
相关推荐
在IT领域,高低字节转换是一项基础且重要的技术,尤其在处理不同计算机体系结构的数据交换时。本项目“高低字节转换示例Demo”提供了一个基于MFC(Microsoft Foundation Classes)的工具,它能帮助用户读取TXT文档中...
5. **网络字节序转换**:在网络通信中,数据传输前需要按照特定的字节顺序(大端或小端)排列。转换工具可能包含功能,用于在不同字节序之间转换。 6. **计算校验和**:为了确保数据传输的完整性,计算校验和(如...
在C++编程中,网络字节顺序转换和IP地址格式转换是网络编程中常见的操作。网络字节顺序,也称为大端字节序,是一种在多处理器系统或网络通信中用于标准化数据表示的方式。IP地址则通常以字符串形式表示,但有时需要...
在易语言中,处理数据时,我们可能会遇到将字节集转换为字节型数组的需求。这在处理二进制数据、网络传输或文件读写等场景中非常常见。下面我们将详细探讨这个主题。 字节集是易语言中用于存储字节序列的数据类型,...
获取网络字节数据转换为字符数据的小工具,供大家使用参考
在IT行业中,尤其是在嵌入式系统、网络通信和数据存储等领域,理解32位浮点数的大小端存储以及高低字节转换是非常重要的基础知识。TIA博途( Totally Integrated Automation Portal)是西门子推出的一款集成自动化...
在易语言中,将文本转换为字节集,主要是为了将文本数据编码成二进制形式,以便于在网络传输或存储中保持数据完整性。易语言提供了“字符串到字节集”这样的函数,可以将字符串类型的文本转换成字节集。例如,我们...
当浮点数需要存储或在网络上传输时,它们会被转换成字节序列。这个过程叫做序列化,反向操作则是反序列化,即将字节序列恢复为原始的浮点数。 这个"字节和float转换小工具"可能包含了以下功能: 1. **字节到浮点数...
当你编写网络程序时,你需要将本地字节序转换为网络字节序,或者反之,这一过程通常称为字节序转换。 Linux中,可以使用以下函数来进行字节序转换: 1. `htons()`(Host to Network Short):将主机字节序的短整型...
在IT行业中,字节转换是编程中不可或缺的一部分,尤其是在处理数据传输、文件解析以及网络通信等领域。字节转换工具能够帮助开发者将数据从一种字节表示形式转换为另一种,以便于理解和操作。以下是对这个“字节转换...
### 网络字节顺序和主机字节顺序的转换 在计算机网络中,不同硬件架构的设备之间进行数据通信时,必须确保数据的一致性和正确性。这其中包括了网络字节顺序(Network Byte Order)与主机字节顺序(Host Byte Order...
2. **字节集到字节型数组的转换**:当需要将字节集转换为字节型数组时,可以使用循环语句,逐个读取字节集内的字节并存入新创建的字节型数组中。下面是一个示例源码: ```易语言 .字节集 = .创建字节集() // 创建一...
在计算机科学中,32位浮点数...总之,理解和掌握浮点数的大小端存储以及高低字节转换在TIA博途中是至关重要的,特别是在进行跨平台或网络通信的程序设计时。通过这个FB块的示例,我们可以更直观地学习并应用这些概念。
浮点数16进制字节转换工具是一种实用的计算机编程辅助工具,它主要用于处理浮点数和十六进制之间的转换。在IT行业中,尤其是在软件开发、数据分析和硬件编程等领域,这种转换是至关重要的。浮点数是计算机科学中表示...
浮点数和4字节数值的相互转换是计算机科学中的一个重要概念,特别是在处理二进制数据、网络传输以及存储时。浮点数是一种表示实数的方法,它使用科学记数法并包括一个符号位、指数部分和尾数部分。4字节数值通常指的...
在易语言中,处理文本和字节集的数据转换是非常常见的操作,尤其是在网络通信、数据存储等领域。本文将详细介绍易语言中如何进行文本与字节集的相互转换,并提供相关知识点。 首先,我们要理解什么是文本和字节集。...
在IT领域,字节转换是一项基础且至关重要的任务,尤其对于编程和网络通信而言。易语言,作为一种简单易学的中文编程语言,被用于创建这个字节和带宽转换小程序,旨在帮助用户理解和处理不同单位的数据量。在这个...
Java 网络字节序转换是编程过程中一个重要的概念,尤其在跨平台通信和处理二进制数据时。字节序是指多字节数据(如整数或浮点数)在内存或文件中存储的顺序。主要有两种字节序:Big-Endian(大端字节序)和 Little-...
字节集是易语言中用于存储一系列字节的数据类型,它通常用于处理二进制数据,如读写文件、网络通信等场景。字节数组则是一种有序的字节序列,它可以方便地进行数组操作,如遍历、索引访问等。在实际编程中,根据需求...
在编程和网络通信领域,理解字节转换至关重要,因为不同系统和协议可能使用不同的字节顺序(如大端序和小端序)或者字符编码(如UTF-8、GBK等)。转换工具能够帮助开发者解决跨平台或跨协议的数据兼容问题。 压缩...