htonl函数是一个网络转换的函数,他把不确定的一个32位数字,转换成网络通用的32位数字,即大头在后的方式。
我们一般使用的计算机都是大头在后,也就是高地址在后面的形式。
比如你定义一个整型变量
int i = 0x12345678
然后在定义一个整型指针
int *p = &i;
假设p的地址是0x0012f2ec
那么在这个地址后4个字节都是这个整数,他的存放形式为
如果是大头前,也就是高地址在前,则存放形式为
0x0012f2ec:12 34 56 78
使用htonl函数后,他的存放形式就便为
0x0012f2ec:78 56 34 12
需要根据操作系统的不同确定你是否需要使用。
htonl = Host To Network, type Long
ntohl = Network To Host, type Long
同理,还有 htons 和 ntohs,这里的 s 是指 short
/***************************************************************************/
x86系统的数据存放都是按照little-endian的格式(硬件层没有对字节序的区分机制)。
通过对Windows平台的字节序转换函数(htons/ntohs(16bit),htonl /ntohl(32bit))的代码的分析,发现Windows对这样的转换没有进行特别的字节序检测,仅仅简单的进行了高低位的转换。
至于为什么没有做检测。我的理解是些转换函数已经默认了参数的字节序(MSDN)。
对于htons,htonl的参数为host byte order(小头);
对于ntohs,ntohl的参数为network byte order(大头)
其实,在调用函数时,我们就隐含指定了数值(注意,可能并非我们定义的数值)。
上面的程序中,可以这样理解。
d = htonl(c);
将小头存放(78’56’34’12)的数值0x12345678 转换为大头存放(12’34’56’78),并附给d。
注意:虽然这时d在小头系统中为0x78563412,但真实的数值是大头序的0x12345678。
e = ntohl(c);
将大头存放(78’56’34’12)的数值0x78563412 转换为小头存放(12’34’56’78),并附给e。
综上所述,导致这个疑问有以下几点。
1.字节序转换函数默认了被转换参数的字节序,所以没有必要再进行检测。
2.对转换后的数值的误解。(d的数值应为0x12345678,而非0x78563412)
3.调用ntohl函数时,对于参数的指定存在误解。
e = ntohl(0x78563412); /*数值0x12345678应该这样指定*/
对于htonl /ntohl代码一样的问题,属x86系统的特例。
如果,有这样一种字节序系统1’3’4’2,对于数值0x12345678的保存形式应该是12’56’78’34。
这个系统上的htonl /ntohl関数的实现应该不会一样的。
也许DiabloWalkOnTheEarth(WorldOfWg( 狗城是个烂代理 )) 所说的机器就是这么一种“非little/big-endian”的字节序,呵呵。
To 0delphi(睡个舒服觉)
的确判别一个 系统 是大头序还是小头序的方法是有的。
比如:
-BEGIN-
int x=1; // 0x00000001
if (*(char*)&x) {
/* little endian. memory image 01 00 00 00 */
}else{
/* big endian. memory image 00 00 00 01 */
}
-END-
内存数据(0x00000001)-〉大头/小头字符序-〉数值(1)
这里判别的前提条件是知道内存数据及所对应的数值,所以可以判定出大小头字符序。
/*************************************************************************************************************/
不同的计算机处理数字有两种形式,big-endian和little-endian型式(
little-endian格式的数据,例如0X12345678以(0X78 0X56 0X34 0X12)方式保存、
big-endian格式的数据,例如0X12345678以(0X12 0X34 0X56 0X78)方式保存 ),这依赖于他们是怎么设计的,比如Intel的x86处理器,多字节是用little-endian型式。IP地址和和端口在电脑中是多字节存放的,他们是host-byte顺序,然而当IP地址和端口通过网络时,必须转成big-endian形式,也就是network-byte顺序
有一系列函数完成两者之间的转换。比如
host-byte序转network-byte序
u_long htonl(u_long hostlong);
int WSAHtonl( SOCKET s, u_long hostlong, u_long FAR * lpnetlong );
u_short htons(u_short hostshort);
int WSAHtons( SOCKET s, u_short hostshort, u_short FAR * lpnetshort );
network-byte序转host-byte序
u_long ntohl(u_long netlong);
int WSANtohl( SOCKET s, u_long netlong, u_long FAR * lphostlong );
u_short ntohs(u_short netshort);
int WSANtohs( SOCKET s, u_short netshort, u_short FAR * lphostshort );