C++ 什么时候持久性成为一个因素?

C++ 什么时候持久性成为一个因素?,c++,networking,stl,endianness,C++,Networking,Stl,Endianness,根据我的理解,Endianness是指组成多字节字的字节顺序不同,至少在最典型的情况下是如此。因此,16位整数可以存储为0xhhl或0xLLHH 假设我没有错,我想知道的是,当在两台计算机之间发送信息时,Endian可能不同,也可能不同,Endian何时会成为一个主要因素 如果我发送一个短整数1,以字符数组的形式,并且没有任何更正,它是否被接收并解释为256 如果我使用下面的代码分解并重新组合短整数,endianness将不再是一个因素吗 // Sender: for(n=0, n <

根据我的理解,Endianness是指组成多字节字的字节顺序不同,至少在最典型的情况下是如此。因此,16位整数可以存储为
0xhhl
0xLLHH

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

  • 如果我发送一个短整数1,以字符数组的形式,并且没有任何更正,它是否被接收并解释为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;
    };
    
    //发送方:
    对于(n=0,n>n)&1;
    };
    //接收人:
    对于(n=0,n值|=uint16(stl_位集[n]&1)端性始终是一个问题。有些人会说,如果你知道连接到网络的每个主机都运行相同的操作系统等,那么你就不会有问题。这是事实,直到它不是。你总是需要发布一个规范,详细说明在线数据的确切格式。它可以是你想要的任何格式,但每个端点都需要了解e格式,并能正确解释

    一般来说,协议使用big-endian表示数值,但如果每个人都不兼容IEEE 754等,这会有局限性。如果您可以承担开销,则使用XDR(或您最喜欢的解决方案)并确保安全

  • 不,尽管你有正确的总体想法。你缺少的是一个事实,即使它通常是串行连接,网络连接(至少大多数网络连接)仍然保证八位字节(字节)的正确端性级别——也就是说,如果在小端机器上发送一个值为0x12的字节,在大端机器上它仍将作为0x12接收

    看一个简短的例子,如果你看十六进制的数字,它可能会有帮助。它以0x0001开头。你把它分成两个字节:0x00 0x01。收到后,它将被读取为0x0100,结果是256

  • 由于网络在八位字节级别处理endianess,因此通常只需补偿字节的顺序,而不必补偿字节中的位

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

  • 补偿的“标准方式”是“网络字节顺序”的概念已经被定义,几乎总是(AFAIK)作为big-endian


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

    请注意,如果您在设备之间传输数据,您几乎应该始终使用n使用
    ntohl
    htonl
    ntohs
    htons
    进行网络字节排序。无论您的系统和目标系统使用什么,它都将转换为网络字节顺序标准,以实现端性。当然,这两个系统都应该这样编程-但它们通常在网络场景中。

    非常有用简而言之,endianness是将变量重新解释为字符数组的属性

    实际上,当您从外部字节流(如文件或套接字)读取()和写入()时,这一点非常重要。或者,抽象地说,当您序列化数据时,endianness非常重要(本质上是因为序列化数据没有类型系统,只由哑字节组成);而endianness在您的编程语言中并不重要,因为该语言只对值进行操作,而不对表示进行操作。从一个到另一个是您需要深入了解细节的地方

    也就是说,写作:

    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);
    
    在这里,我们可以说,
    重新解释cast(&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
    
    unsigned char buf[4]=read_data();
    
    uint32_t n_LE=buf[0]+buf[1]你不必担心,除非你在系统的边界。通常,如果你在谈论stl,你已经通过了边界

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


    如果你说的是内置的,那么你可能已经满足了[C/C++endian中性代码的机器抽象要求。这里有一些C/C++endian中性代码的指导原则。显然,这些都是作为“避免的规则”编写的……因此,如果代码有这些“特性”,它可能容易出现与endian相关的错误!!(这是我在Dobbs博士上发表的关于Endianness的文章)

  • 避免使用组合不同多字节数据类型的联合。 (活接头的布局可能具有不同的endian相关顺序)

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

  • 避免使用位字段和字节掩码 (由于存储器的布局取决于尾数,字节的屏蔽和位字段的选择是尾数敏感的)

  • 避免将指针从多字节类型转换为其他字节类型。
    (指针从一种类型转换为另一种类型时,源(即原始目标)的终止性将丢失,后续处理可能不正确)


  • 据我所知,这两种终端都有一个优势:

  • Big-endian在概念上更容易理解,因为它类似于我们的位置数字系统:从最重要到最不重要
  • 在重用内存时,Little endian非常方便