什么时候是htonl(x)!= ntohl(x)?(或者在同一台计算机上进行与网络字节顺序的转换时不相同?)

sel*_*bie 7 sockets endianness

关于htonlntohl.何时将这两行代码中的任何一行评估为false.

 htonl(x) == ntohl(x);

 htonl(ntohl(x)) == htonl(htonl(x));
Run Code Online (Sandbox Code Playgroud)

换句话说,这两个操作何时在同一台机器上不相同?我能想到的唯一场景是一台机器,它不能用于表示整数的2的补码.

原因主要是历史,编码清晰度还是其他原因?

今天是否存在任何现代架构或环境,在这两个方向上,这些在同一台机器上的网络字节顺序转换是不同的代码?

sel*_*bie 6

我找不到Posix规范的原始草稿,但最近在网上发现的一个提示.

网络字节顺序可能不便于处理实际值.为此,将值存储为普通整数更为明智.这称为"主机字节顺序".在主机字节顺序中:

The most significant bit might not be stored in the first byte in address order.

**Bits might not be allocated to bytes in any obvious order at all.**
Run Code Online (Sandbox Code Playgroud)

存储在uint8_t对象中的8位值不需要转换为主机字节顺序或从主机字节顺序转换,因为它们具有相同的表示形式.可以使用htonl(),htons(),ntohl()和ntohs()函数转换16位和32位值.

有趣的是,以下陈述是在讨论下作出的

POSIX标准明确要求8位字符和二进制补码算法.

所以这基本上排除了我对1的补码机器实现的想法.

但是"任何明显的命令"声明基本上都表明posix委员会至少考虑过posix/unix运行于大端或小端的其他东西的可能性.因此,不能排除声明htonl和ntohl作为不同的实现.

所以简短的回答是"htonl和ntohl是相同的实现,但两个不同功能的接口是为了将来与未知的兼容性."


小智 5

多年前我为UNIVAC 1100系列主机编写了一个TCP/IP堆栈.这是一个36位,可字寻址的计算机体系结构,具有1的补码算法.

当这台机器进行通信I/O时,来自外部世界的8位字节将被放入每个9位四分之一字的低8位.因此在这个系统上,ntohl()会将每个四分之一字中的8位压缩到字的低32位(前4位为零),因此您可以对其进行算术运算.

同样,htonl()将取一个字中的低32位并撤消此操作,以将每个8位数量放入每个9位四分之一字的低8位.

因此,为了回答原始问题,这个计算机体系结构上的ntohl()和htonl()操作彼此非常不同.

例如:

COMP*                                 . COMPRESS A WORD
          LSSL      A0,36             . CLEAR OUT A0
          LSSL      A1,1              . THROW AWAY TOP BIT
          LDSL      A0,8              . GET 8 GOOD ONE'S
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          J         0,X9              .
.
DCOMP*                                . DECOMPRESS A WORD
          LSSL      A0,36             . CLEAR A0
          LSSL      A1,4              . THROW OUT NOISE
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          J         0,X9              .
Run Code Online (Sandbox Code Playgroud)

COMP等同于ntohl()和DCOMP到htonl().对于那些不熟悉UNIVAC 1100汇编代码的人:-) LSSL是"Left Single Shift Logical"的一个寄存器,由多个位置组成.LDSL是指定计数的"左双移逻辑"对的一对寄存器.因此LDSL A0,8将连接的A0,A1寄存器移位8位,将A1的高8位移入A0的低8位.

这段代码是1981年为UNIVAC 1108编写的.几年后,当我们有一个1100/90并且它开发了一个C编译器时,我开始了一个BSD NET/2 TCP/IP实现的端口并实现了ntohl()和htonl ()以类似的方式.可悲的是,我从未完成那项工作..

如果你想知道为什么有些互联网RFC使用术语"八位字节",那是因为当天的某些计算机(如PDP-10,Univacs等)的"字节"不是8位."八位字节"专门定义为8位字节.