我在little-endian [LE]机器[Linux,Intel处理器]上运行了以下程序。我无法在下面的代码片段中解释3个输出。由于机器是LE,因此a
的值存储为0x78563412
。打印时,它显示其实际值。由于它是LE机器,我希望ntohl()
是一个无操作并显示0x78563412
,它正在做。但是,对于包含0x12345678
的第二个打印语句,我希望htonl()
。有人可以帮我理解为什么它们一样吗?
int main()
{
int a = 0x12345678;
printf("Original - 0x%x\n", (a));
printf("Network - 0x%x\n", htonl(a));
printf("Host - 0x%x\n", ntohl(a));
return 0;
}
输出:
Original - 0x12345678
Network - 0x78563412
Host - 0x78563412
答案 0 :(得分:23)
由于它是LE机器,我希望
ntohl()
成为无操作
这是错误的。网络字节顺序为 big-endian ,主机字节顺序为little-endian。因此,ntohl
和htonl
都会返回其输入的字节交换版本。
请记住,htonl
的要点是您可以在主机上取整数,然后写:
int i = htonl(a);
结果是i
,的内存在使用网络字节顺序解释时,具有与a
相同的值。因此,如果将i
的对象表示写入套接字,而另一端的阅读器需要网络字节顺序的4字节整数,则它将读取a
的值。
并显示
0x78563412
这是你打算写的吗?如果ntohl
是无操作(或者更确切地说是身份函数),那么您的第三行必然会打印与第一行相同的内容,因为您将拥有ntohl(a) == a
。这是在程序打印的big-endian实现中发生的事情:
Original - 0x12345678
Network - 0x12345678
Host - 0x12345678
答案 1 :(得分:11)
htonl
和ntohl
功能完全相同。他们应该满足htonl(ntohl(x)) == x
。它们的命名方式不同仅适用于文档(您明确指出要从主机到网络或其他方式进行转换,即使它们是相同的)。因此,在小端机器上,它们都执行字节交换,而在大端机器上,它们都是无操作的。
答案 2 :(得分:5)
因为您按值传递a
因此不会被其中任何一个函数更改。
您正在打印htonl()
和ntohl()
返回的内容。
编辑添加:我错过了您认为其中一个无操作的地方。不是。两者都将在LE机器上做同样的事情;反转字节排序。 ntohl()
期待您传递一个排序为int
答案 3 :(得分:0)
在您的程序中,当您编写int a;
知道a
包含主机有序整数时,程序并不知道。您可以轻松地提供已经包含网络顺序值的int。当然,如果对非主机顺序的值使用任何算术运算符,如果网络顺序与主机顺序不同,则从网络角度来看结果将是错误的。
但目前还不是这样,网络有序值通常在低级结构中保持这种状态,在发送之前或刚接收之后。
你的程序有什么问题,当你致电ntohl()
时,你承诺ntohl()
函数,你提供的int
是一些以网络顺序存储在内存中的值。这是合同。如果不成功,该功能将无法满足您的期望,而这正是您所期待的。
正如大多数系统(大或小但不是愚蠢的端)所解释的那样,这两个函数通常是相同的,无论是字节反转还是无操作。