16

我在 little-endian [LE] 机器 [Linux,Intel 处理器] 上运行了以下程序。我无法解释下面代码片段中的 3 个输出。由于机器是 LE,所以 的值a存储为0x78563412。打印时,它显示其实际值。由于它是一台 LE 机器,我希望ntohl()它是一个 no-op 和 display 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
4

4 回答 4

26

由于它是一台 LE 机器,我希望ntohl()它是一个空操作

这就是错误。网络字节顺序是big-endian,主机字节顺序是 little-endian 。因此,两者都ntohl返回htonl其输入的字节交换版本。

记住,重点htonl是你可以在主机上取一个整数,然后写:

int i = htonl(a);

结果是 的内存i当使用网络字节顺序解释时,具有相同的值a。因此,如果您将 的对象表示写入i套接字并且另一端的读取器期望网络字节顺序中的 4 字节整数,它将读取 的值a

并显示0x78563412

这是你打算写的吗?如果ntohl是一个无操作(或者更确切地说,一个标识函数),那么您的第三行必然会打印与您的第一行相同的内容,因为您将拥有ntohl(a) == a. 这就是在大端实现中发生的情况,您的程序会在其中打印:

Original - 0x12345678
Network - 0x12345678
Host - 0x12345678
于 2012-07-10T23:15:15.023 回答
18

htonl并且ntohl是完全相同的功能。他们应该满足htonl(ntohl(x)) == x。它们的命名不同仅用于文档(您明确表示您正在从主机转换为网络或其他方式,即使它是相同的)。因此,在 little-endian 机器上,它们都执行字节交换,而在 big-endian 机器上,它们都是无操作的。

于 2012-07-10T23:15:38.717 回答
6

因为您是a按值传递的,因此这些函数中的任何一个都不会更改它。

你正在打印什么htonl()并且ntohl()正在返回

编辑补充:我错过了你认为没有操作的地方。它不是。两者都将在 LE 机器上做完全相同的事情。反转字节顺序。ntohl()期望你传递一个有序的网络字节int

于 2012-07-10T23:13:40.353 回答
0

在您编写的程序中,int a; 知道其中a包含一个主机有序整数,但程序不知道这一点。您可以轻松地提供一个已包含网络顺序值的 int。当然,如果您对不按主机顺序的值使用任何算术运算符,如果网络顺序与主机顺序不同,则从网络的角度来看,结果将是不正确的。

但这并不是那么牵强,网络有序值通常在低级结构中完全保持这种方式,在发送之前或刚刚接收之后。

您的程序有什么问题是,当您调用时,ntohl()您承诺您提供的ntohl()功能int是以网络顺序存储在内存中的一些值。这就是合同。如果它不是真的,该功能将不会执行您所期望的,这就是您所看到的。

正如其他在大多数系统(大或小但不是愚蠢的字节序)上所解释的那样,这两个函数通常是相同的,要么是字节反转,要么是无操作。

于 2014-10-31T16:45:54.600 回答