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

Ann*_*inn 68 c++ networking stl endianness

根据我的理解,字节顺序是组成多字节字的字节顺序不同,至少在最典型的情况下.这样一个16位整数可以存储为0xHHLL或者0xLLHH.

假设我没有那个错误,我想知道的是,当Endian可能会或可能没有不同的两台计算机之间发送信息时,Endianness何时成为主要因素.

  • 如果我以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;
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • 是否有补偿字节序的标准方法?

提前致谢!

Ker*_* SB 50

非常抽象地说,字节序是将变量重新解释为char数组的属性.

实际上,这对于您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);
Run Code Online (Sandbox Code Playgroud)

在这里我们可以说,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
Run Code Online (Sandbox Code Playgroud)

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


正如您所看到的,如果使用代数输入和输出操作,使用整数类型,您永远不必知道自己系统的字节序,只知道数据流的字节序.对于其他数据类型double,问题更复杂.

  • @phkahler:这是一个彻底的声明,我不会宽恕这一点.您可以编写大量有用的程序,这些程序可以在不同的平台上运行,而且从不需要了解其类型的二进制表示. (4认同)

Joh*_*0te 35

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

  • 没问题 - 在你不得不使用它们之前,它们是你不会想要的东西之一.一个很好的技巧是根据输入模板参数的长度创建一个使用htons/htonl转换的模板 - 这是在一个函数中将简单类型转换为网络排序的一种非常有效的方法:) (2认同)

Jer*_*fin 7

  1. 不,虽然你确实有正确的总体想法.你所缺少的是这样的事实,即使它通常是串行连接,网络连接(至少大多数网络连接)仍然保证八位字节(字节)级别的正确字节顺序 - 即,如果你发送一个带有值的字节在小端机器上的0x12,它仍然会在大端机器上被接收为0x12.

    看一下,如果你看一下十六进制的数字,它可能会有所帮助.它从0x0001开始.你将它分成两个字节:0x00 0x01.收到后,它将被读为0x0100,结果为256.

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

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


Ray*_*oal 6

补偿的"标准方式"是"网络字节顺序"的概念已被定义,几乎总是(AFAIK)作为大端.

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


amo*_*oss 6

这两个结尾都有一个我所知道的优势:

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


No *_*lar 5

Endianness总是一个问题.有人会说,如果你知道连接到网络的每个主机运行相同的操作系统等,那么你就不会有问题.这是真的,直到它不是.您始终需要发布详细说明在线数据的EXACT格式的规范.它可以是您想要的任何格式,但每个端点都需要了解格式并能够正确解释它.

一般来说,协议使用big-endian来表示数值,但是如果每个人都不兼容IEEE 754等,这就有局限性.如果你可以节省开销,那么使用XDR(或你最喜欢的解决方案)并保证安全.

  • 我反对的是,字节序总是*一个问题.相反,它始终是*序列化数据格式*的问题.在特定情况下,特定机器的字节顺序可能完全无关紧要. (9认同)