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

从我所理解的字节顺序来看,组成多字节字的字节在顺序上是不同的,至less在最典型的情况下是这样。 因此,一个16位整数可能被存储为0xHHLL0xLLHH

假设我没有这个错误,我想知道什么时候Endianness在两台计算机之间发送信息的时候成为一个主要的因素,Endian可能不一样。

  • 如果我发送一个短整数1,以char数组的forms,没有更正,它是否被接收并解释为256?

  • 如果我使用下面的代码分解和重新构造短整数,endianness不再是一个因素?

     // 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; }; 
  • 是否有一个标准的方式来补偿sorting?

提前致谢!

非常抽象地说,字节序是将variables重新解释为字符数组的一个属性。

实际上,当你从外部字节stream(如文件或套接字) read()write()时,这一点至关重要。 或者,再次抽象地讲,当序列化数据时,sorting很重要(本质上是因为序列化的数据没有types系统,只是由哑字节组成)。 而且您的编程语言中字节顺序并不重要,因为该语言只能在上运行,而不是在表示上运行 。 从一个到另一个是你需要深入细节的地方。

为了智慧 – 写作:

 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) ,结果将取决于机器的字节顺序。

正如你所看到的那样,如果使用代数input和输出操作,使用整数types,你永远不必知道你自己的系统的sorting,只有数据stream。 与其他数据types如double ,问题更复杂。

为了logging,如果你正在设备之间传输数据,你应该几乎总是使用ntohlhtonlntohshtonsnetworking字节顺序。 无论您的系统和目标系统如何使用,它都将转换为networking字节顺序标准。 当然,这两个系统都应该像这样编程 – 但他们通常在networking场景中。

  1. 不,虽然你有正确的概念。 你所遗漏的是,即使通常是一个串行连接,networking连接(至less大多数networking连接)仍然保证在八位字节(字节)级别上的正确的字节顺序 – 即,如果你发送一个字节的值在一个小端机器上的0x12,它仍然会在大端机器上被接收为0x12。

    纵观一下,如果你看hex的数字,这可能会有帮助。 它开始为0x0001。 你把它分成两个字节:0x00 0x01。 一旦收到,这将被读为0x0100,结果是256。

  2. 由于networking处理八位字节的字节数,所以通常只需要补偿字节的顺序,而不是字节内的位。

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

补偿的“标准方式”是“networking字节顺序”的概念已经定义,几乎总是(AFAIK)作为大端。

发送者和接收者都知道有线协议,并且如果有必要的话会在发送之前和接收之后进行转换,给应用程序提供正确的数据。 但是这种翻译发生在你的networking层 ,而不是在你的应用程序中。

两个endianesses有我知道的一个好处:

  1. 大端在概念上更容易理解,因为它类似于我们的位置数字系统:最重要的是最不重要的。
  2. 在重复使用多个内存大小的内存引用时,Little-endian很方便。 简单地说,如果你有一个指向小端unsigned int*的指针,但是你知道存储的值是<256,你可以把指针转换成unsigned char*

字节顺序总是一个问题。 有人会说,如果你知道连接到networking的每台主机都运行相同的操作系统等,那么你不会有问题。 这是真的,直到它不是。 您总是需要发布详细说明在线数据的精确格式的规格。 它可以是任何你想要的格式,但每个端点都需要理解格式并能正确解释。

一般来说,协议使用big-endian来表示数值,但是如果每个人都不是IEEE 754兼容的话,那么协议就会受到一些限制。如果你能承担这些开销,那么使用XDR(或者你最喜欢的解决scheme)并且是安全的。

这里是C / C ++的endian-neutral代码的一些指导。 显然,这些都写成“避免的规则”…所以如果代码具有这些“function”,它可能会容易产生endian相关的错误! (这是从我在Dobbs博士发表的关于Endianness的文章)

  1. 避免使用组合不同多字节数据types的联合。 (联盟的布局可能有不同的端联令)

  2. 避免访问字节数据types之外的字节数组。 (字节数组的顺序有一个endian相关的顺序)

  3. 避免使用位域和字节掩码(因为存储的布局取决于字节顺序,字节掩码和位域select是端到端敏感的)

  4. 避免将指针从多字节types转换为其他字节types。
    (当一个指针从一个types转换到另一个types时,源代码(即原始目标)丢失,后续处理可能不正确)

你不必担心,除非你在系统的边界。 通常情况下,如果你正在谈论stl,你已经通过了这个边界。

指示/确定一系列字节如何转换成你发送的types是一个内置types或者一个自定义types,这是序列化协议的任务。

如果你只是在内置的话,你可能已经足够了由你的环境提供的工具提供的机器抽象]