关于windows、VC中的ntohl/htonl,多谢!

toyjoy 2006-02-22 09:06:38
void main()
{
unsigned long c = 0x12345678;
unsigned long d = 0;
unsigned long e = 0;

d = htonl(c);
e = ntohl(c);

printf("1=%x\n", c);
printf("2=%x\n", d);
printf("3=%x\n", e);
}

为什么d、e的值是一样的?难道这两个函数不能自动判断本地的字节序,
而只是简单的将参数中的变量c的字节序颠倒就完了?

...全文
2037 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
tudou614 2006-02-23
  • 打赏
  • 举报
回复
mark
  • 打赏
  • 举报
回复
hton、ntoh两个函数得出的结果理论上完全应该是一样的, 只要不是像字节序为奇怪的 2314 这样古怪机器.
toyjoy 2006-02-22
  • 打赏
  • 举报
回复
多谢楼上各位的解答!

我的意思中有两点:
1、windows、VC开发环境
2、hton、ntoh两个函数得出的结果一样,理论上应该是不一样的,个人感觉,所以比较奇怪
奥爸 2006-02-22
  • 打赏
  • 举报
回复
htonl和ntohl 这两个函数不一定进行格式颠倒,如果本机格式跟网络格式不一样的话,才进行颠倒.格式一样的话不颠倒的
奥爸 2006-02-22
  • 打赏
  • 举报
回复
htonl和ntohl主要是为了防止在不同平台的机器数据存放格式不同
在同一个机器上没有任何区别
alen_ghl 2006-02-22
  • 打赏
  • 举报
回复
就是颠倒顺序
自己也可以写
比如写一个对64位整数的转换
Joe_Cai 2006-02-22
  • 打赏
  • 举报
回复
虽然htonl和ntohl在实现上是一样的,但是我们在语意上要明确它们是2个不同的函数!
robin_yao 2006-02-22
  • 打赏
  • 举报
回复
gz
shinka 2006-02-22
  • 打赏
  • 举报
回复
我想你的猜测是对的。
至少在VC6.0环境中,这两个函数不但没有自动判断本地的字节序,甚至连函数的代码(汇编)都是完全一样的。
我们可以简单验证一下。

void main()
{
unsigned long c = 0x12345678;
unsigned long d = 0;
unsigned long d1 = 0;
unsigned long e = 0;
unsigned long e1 = 0;

d = htonl(c);
d1 = htonl(d);
e = ntohl(c);
e1 = ntohl(e);

printf("1=%x\n", c);
printf("2=%x\n", d);
printf("3=%x\n", d1);
printf("4=%x\n", e);
printf("5=%x\n", e1);
}

对e,d调用两次转换函数的结果e1,d1的值,反反得正又成为0x12345678(即c)。
以上。
  • 打赏
  • 举报
回复
还没见过哪个平台下 ntohl 和 htonl 会不一样的 ....
Joe_Cai 2006-02-22
  • 打赏
  • 举报
回复
Windows平台上“字节序”是确定的,还用判断吗?MS在Windows平台上实现函数htonl()和ntohl()的时候,他当然知道“字节序”!
shinka 2006-02-22
  • 打赏
  • 举报
回复

以下是我对这个问题的归纳整理。

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)
这里判别的前提条件是知道内存数据及所对应的数值,所以可以判定出大小头字符序。

谢谢各位:)
antter 2006-02-22
  • 打赏
  • 举报
回复
我以前查到并译注的.

字节顺序
不同的计算机处理数字有两种形式,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 );

奥爸 2006-02-22
  • 打赏
  • 举报
回复
汇编不懂,冷汗.........(需要进行大量学习)
不过判断big endian 和 little-endian 函数有很多.
Big-endian for Solaris SPARC system and little-endian for Solaris x86 and x64 system

shinka 2006-02-22
  • 打赏
  • 举报
回复
DiabloWalkOnTheEarth(WorldOfWg( 狗城是个烂代理 )) 误解我的意思了。
我对0delphi(睡个舒服觉)有疑问的地方:

不是“不需要颠倒”。
而是“在x86+Windows平台下,htonl和ntohl 这两个函数不一定进行格式颠倒”。

PS:突然觉得我可能也误解0delphi的意思了:) (如果不限定平台的话,你说的没错。)
如果是的话,不好意思了。
  • 打赏
  • 举报
回复
世界上字节序不同于 X86 的机器多的是, 大端序的机器本身内部字节序就是网络字节序, 当然不需要颠倒.
shinka 2006-02-22
  • 打赏
  • 举报
回复
To:0delphi(睡个舒服觉)

>htonl和ntohl主要是为了防止在不同平台的机器数据存放格式不同
>在同一个机器上没有任何区别

htonl和ntohl函数并不会防止什么。
他们是为不同平台数据存放格式(字节序)的相互转换提供了一种方法。
不管是不是同一个机器,至少,在x86平台机器(little-endian)利用网络IP地址(Network-byte big-endian)的情况下,字节序的转换是必要的。

>htonl和ntohl 这两个函数不一定进行格式颠倒,如果本机格式跟网络格式不一样的话,
>才进行颠倒.格式一样的话不颠倒的

不知道你是如何得出这样的结论?
请问
1.事实上这两个函数的确进行了格式颠倒,为什么你说不一定呢?
*下面列出了这两个函数的汇编代码(两个函数的代码完全一致)。
2.按你的说法,本机格式跟网络格式在内部又是如何判别的呢?

-BEGIN-
719E2BC0 mov edi,edi
719E2BC2 push ebp
719E2BC3 mov ebp,esp
719E2BC5 mov ecx,dword ptr [ebp+8]
719E2BC8 mov eax,ecx
719E2BCA mov edx,ecx
719E2BCC shl edx,10h
719E2BCF and eax,0FF00h
719E2BD4 or eax,edx
719E2BD6 mov edx,ecx
719E2BD8 and edx,0FF0000h
719E2BDE shr ecx,10h
719E2BE1 or edx,ecx
719E2BE3 shl eax,8
719E2BE6 shr edx,8
719E2BE9 or eax,edx
719E2BEB pop ebp
719E2BEC ret 4
-END-

以上。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧