Endianness什么时候成为一个因素?


71

据我了解,字节序是指组成多字节字的字节的顺序不同,至少在最典型的情况下如此。这样16位整数可以存储为0xHHLL0xLLHH

假设我没有记错,我想知道的是,Endianness何时成为在两台计算机之间(Endian可能不同)的主要因素,而Endian可能不同。

  • 如果我以char数组的形式传输短整数1,并且没有进行任何更正,是否接收并将其解释为256?

  • 如果我使用以下代码分解和重新组合短整数,则字节序将不再是一个因素吗?

    // Sender:
    for(n=0, n < sizeof(uint16)*8; ++n) {
        stl_bitset[n] = (value >> n) & 1;
    };
    
    // Receiver:
    for(n=0, n < sizeof(uint16)*8; ++n) {
        value |= uint16(stl_bitset[n] & 1) << n;
    };
    
  • 是否存在补偿字节序的标准方法?

提前致谢!


10
+1非常有趣的问题!顺便说一句,它会被解释为0100(0d256),因为字节交换,而不是位:)
BlackBear

2
我不知道为什么没有人问关于字节顺序-为1表示0000000110000000;-)
Kerrek SB

2
不要忘记“在两台计算机之间发送信息”不仅包括网络,而且还包括写在一台计算机上并以某种方式传输到另一台计算机上的文件。因此,每种二进制文件格式都必须具有完全指定的字节序。
mmmmmmmm 2011年

9
我不得不说,尽管我知道您在写什么,0xHHLL以及类似的东西,但我认为这不是表示该概念的好方法,因为0x...它是在语言语法级别上构造的,而字节序在内存组织级别上。也就是说0xFF120xFF12对机器的每个字节序。通常的构造是使用十六进制编辑器类型的输出或将内存绘制为其中包含值的盒子数组。
dmckee ---前主持人小猫,

1
htons,htonl,ntohs,ntohl ... Endiness是指不同体系结构存储Integer类型之间的区别。它成为处理套接字时的主要因素。假设您要序列化包含一些短裤和一些长号的结构。您需要使用适当的功能来确保通过电线发送的数据以正确的顺序(网络中性顺序)发送到目的地。同样,此类数据的客户将不得不从网络转换为主机订单。ntohl(长主机网络)等。很自我解释。
johnathan

Answers:


50

从抽象上讲,字节序是将变量重新解释为字符数组的属性。

实际上,当您read()往返write()于一个外部字节流(例如文件或套接字)时,这一点尤为重要。或者,再次抽象地说,当您对数据进行序列化时,字节顺序很重要(本质上是因为序列化的数据没有类型系统,仅由哑字节组成);端序您的编程语言中并不重要,因为该语言仅对值起作用,而对表示形式不起作用。从一个到另一个是您需要深入研究细节的地方。

机智-写作:

uint32_t n = get_number();

unsigned char bytesLE[4] = { n, n >> 8, n >> 16, n >> 24 };  // little-endian order
unsigned char bytesBE[4] = { n >> 24, n >> 16, n >> 8, n };  // big-endian order

write(bytes..., 4);

在这里,我们可以说,,reinterpret_cast<unsigned char *>(&n)而结果将取决于系统的字节序。

并阅读:

unsigned char buf[4] = read_data();

uint32_t n_LE = buf[0] + buf[1] << 8 + buf[2] << 16 + buf[3] << 24; // little-endian
uint32_t n_BE = buf[3] + buf[2] << 8 + buf[1] << 16 + buf[0] << 24; // big-endian

同样,在这里我们可以说,,uint32_t n = *reinterpret_cast<uint32_t*>(buf)并且结果将取决于机器的字节序。


如您所见,对于整数类型,如果您使用代数输入和输出操作,则不必知道系统本身的字节序,而只需知道数据流的字节序即可。对于其他数据类型,例如double,问题更加复杂。


我一直想知道字节序在范围上是否达到了多远,是否影响了程序所在的程序(因此,需要担心按位操作和位移的方向等),或者这仅仅是网络问题。但是,当您将其置于仅影响数据流的上下文中时,对我来说更有意义。
安妮·奎因

@Clairvoire:如果您在具有不同字节序的不同平台上运行相同的代码,则字节序在编程语言中确实很重要。
phkahler 2011年

4
@phkahler:这是一个笼统的声明,我一般不会对此宽容。您可以编写许多有用的程序,它们可以在不同的平台上运行,而无需了解有关其类型的二进制表示的任何信息。
Kerrek SB 2011年

1
@Kerrek:我应该说“可以”或“在不同字节序的平台之间保存或传输二进制数据时”设置条件。是的,我太笼统了。
phkahler 2011年

35

为了记录在案,如果你的设备之间传输数据,你应该几乎总是使用网络字节顺序有ntohlhtonlntohshtons。无论系统和目标系统使用什么,它将转换为字节序的网络字节顺序标准。当然,两个系统都应该像这样编程-但它们通常都在网络环境中。


在您回答之前,我从未听说过这些,因此,我一定会查找它们,谢谢!
安妮·奎因

2
没问题-它们是您必须使用它们之前不知道要寻找的东西之一。一个不错的技巧是使模板根据输入模板参数的长度使用htons / htonl进行转换-这是一种将简单类型转换为网络排序的有效方法:)
John Humphreys-w00te 2011年

1
到底在说什么?Beej的《网络编程指南》将告诉您:beej.us/guide/bgnet
h0b0 2011年

7
  1. 不,尽管您确实有正确的总体思路。您所缺少的是以下事实:即使通常是串行连接,网络连接(至少大多数网络连接)仍可以保证八位字节(字节)级别的正确字节序-即,如果您发送带有值的字节在小型endian机器上为0x12,在大型endian机器上仍为0x12。

    看短一点,如果您看十六进制的数字,可能会有所帮助。它开始为0x0001。您将其分为两个字节:0x00 0x01。收到后,将其读取为0x0100,结果为256。

  2. 由于网络在八位位组级别处理字节序,因此通常只需要补偿字节顺序,而不需要补偿字节内的位。

  3. 可能最简单的方法是在发送时使用htons / htonl,在接收时使用ntohs / ntohl。如果这还不够的话,有很多替代方案,例如XDR,ASN.1,CORBA IIOP,Google协议缓冲区等。


哦,哎呀!当我编写示例代码时,我并没有想到这一点。我的意图是显示将位存储到位集中的方式,只是使它们的存储和检索方式相同,因为我认为位移位会忽略字节序AFAIK。我应该在字节级别上做到这一点,以使其更清楚(更有效)。我将尝试使用google的缓冲区,它们似乎很有趣!
安妮·奎因

6

补偿的“标准方式”是已经定义了“网络字节顺序”的概念,几乎总是将其定义为大字节序。

发送方和接收方都知道有线协议,并且如有必要,将在发送之前和接收之后进行转换,以为应用程序提供正确的数据。但是这种转换发生在您的网络层内部,而不是您的应用程序中。


6

我知道,这两个端点都有一个优势:

  1. 大端在概念上更易于理解,因为它与我们的位置数字系统相似:从最高有效到最低有效。
  2. 对于多个内存大小重用内存引用时,little-endian十分方便。简而言之,如果您有一个指向小尾数的指针,unsigned int*但是您知道那里的存储值小于256,则可以将指针转换为unsigned char*

5

字节序总是一个问题。有人会说,如果您知道连接到网络的每个主机都运行相同的OS等,那么您就不会有问题。直到不是这样,这都是事实。您始终需要发布详细说明在线数据精确格式的规范。它可以是您想要的任何格式,但是每个端点都需要了解该格式并能够正确解释它。

通常,协议使用big-endian来表示数值,但是如果每个人都不兼容IEEE 754等,则存在局限性。如果可以承担开销,请使用XDR(或您最喜欢的解决方案)并且安全。


9
我反对字节序始终是一个问题。相反,对于序列化数据格式而言,这始终是一个问题。在某些情况下,特定计算机的字节序可能完全不相关。
Kerrek SB 2011年

4

这是C / C ++字节序无关代码的一些准则。显然,这些被写为“要避免的规则”……因此,如果代码具有这些“功能”,则很可能会出现与字节序相关的错误!(摘自Dobbs博士发表的有关Endianness的文章)

  1. 避免使用结合了不同的多字节数据类型的并集。(联合的布局可能具有与字节序相关的不同顺序)

  2. 避免访问字节数据类型之外的字节数组。(字节数组的顺序具有与字节序相关的顺序)

  3. 避免使用位字段和字节掩码(由于存储的布局取决于字节序,因此字节的掩码和位字段的选择对字节序敏感)

  4. 避免将指针从多字节类型转换为其他字节类型。
    (当将指针从一种类型强制转换为另一种类型时,源(即原始目标)的字节序丢失,并且后续处理可能不正确)



3

除非您处于系统边界,否则不必担心。通常,如果您使用的是stl,那么您已经通过了该边界。

序列化协议的任务是指示/确定如何将一系列字节转换为要发送的类型,无论是内置类型还是自定义类型。

如果您仅是内置的,则可以满足您的环境提供的工具提供的机器抽象]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.