big endian和little endian值是否可移植?

时间:2014-12-09 15:47:32

标签: c++ c memory-management endianness

你好,我有一个小端dout和大端的小dout我知道这个问题已经问了n次,但我无法弄清楚以下几点

让int i = 10它在二进制文件中以00000000 00000000 00000000 00001010的形式存储在堆栈部分中,如下所示: -

00000000 |00000000 |00000000 |00001010   // In case of little endian
MSB-------------------------------------------LSB

Big endian

00001010 |00000000 |00000000 |00000000   // In case of in big endian
MSB-------------------------------------------LSB

在这个小端和大端都会给出相同的输出10?

那么这些小端和大端的用途是什么?


我被要求实现代码,这些代码在我的访谈中对于所有大小系统都是可移植的。我回答说:

  

编译器会自行完成,如果int i = 10 in little endian,那么在big endian中它也是10作为输出

答案是否正确?

4 个答案:

答案 0 :(得分:4)

00000000 | 00000000 | 00000000 | 00001010 // big    endian

00001010 | 00000000 | 00000000 | 00000000 // little endian

数据是以big endian还是little endian模式存储,这通常只会影响您是否尝试通过指针访问内存中较小部分的变量,例如尝试访问a中最不重要的字符。通过指向字符的指针或带字符数组的并集的32位整数。另一个问题的例子是,如果您将文件中的数据直接读取到32位整数数组中,或者从32位整数数组中读取数据。文件中的数据通常也会以小端或大端模式存储。

据我所知,没有通用的编译时方法来确定cpu是以大端模式还是小端模式运行(特定编译器可能已为此定义)。您可以使用32位整数和大小为4的字符数组的并集编写测试代码。然后将union中的整数设置为10,并检查union字符数组[0]是否包含10表示小端模式,或者如果联合字符数组[3]包含10,这意味着大端模式。可以使用其他方法来确定CPU是处于小端还是大端模式。

一旦确定cpu是处于小端还是大端模式,就可以包含条件代码来处理这两种情况,例如来自/来自32位整数数组的文件I / O.如果您希望文件数据处于大端模式,但您的cpu处于小端模式,则在写入之前或从文件读取之后,您必须反转每个整数的字节。

您也可以编写代码序列来以big endian模式存储数据,而不管cpu模式如何。如果已经处于大端模式,它将浪费时间,但它适用于大端和小端模式:

char     buffer[256];
char *   ptr2char;
uint32_t uint32bit;
/* ... */
    ptr2char = buffer;    /* store uint32bit in big endian mode */
    *ptr2char++ = (uint32bit >> 24)&0xff;
    *ptr2char++ = (uint32bit >> 16)&0xff;
    *ptr2char++ = (uint32bit >>  8)&0xff;
    *ptr2char++ = (uint32bit      )&0xff;

答案 1 :(得分:1)

只需更正整数的图表:int i = 10;

// Big endian
&i <- address of i
00000000 |00000000 |00000000 |00001010 // In case of big endian

MSB---------------------------LSB


// Lower memory -----------------> higher memory


// Little endian

00001010 |00000000 |00000000 |00000000 // In case of in little endian
&i <- address of i
LSB---------------------------MSB

little endian 中,最低有效字节(LSB)存储在最低内存地址中。

big endian 中,最高有效字节(MSB)存储在最低内存地址中。

答案 2 :(得分:1)

首先:您确实混淆了大端和小端字节顺序,正如@rcgldr's@Galik's答案中所指出的那样。正如您在样本中显示的那样,字节顺序完全相反:

00000000 | 00000000 | 00000000 | 00001010 // big endian

00001010 | 00000000 | 00000000 | 00000000 // little endian

至于你的假设和问题:

  

&#34;在这个小端和大端都会给出相同的输出10?&#34;

这取决于您所指的 输出类型

  1. 无论主机是什么,以下代码都是可移植的。 endianess,输出格式化文本("10")在任何情况下:

  2. int i = 10;
    
    std::cout << i << std::endl;
    

    1. 以下代码不可移植。由于值是以二进制形式写入的,因此字节顺序将保持逐字:

    2. int i = 10;
      
      std::ofstream binfile("binaryfile.bin");
      binfile.write((const char*)&i,sizeof(int));
      

      如果应在具有不同字节顺序的主机上读取文件,则后一个示例将无效。

      为了解决这类问题,htonl(), ntohl()函数族已经出现。通常,人们同意使用网络字节顺序(big-endian)格式来存储二进制数据或通过网络发送它。

      这是一个简短的示例,如何使用上面提到的字节顺序转换函数:


      int i = 10;
      int sendValue = htonl(i); // convert the value of i to network byte order
      
      std::ofstream binfile("binaryfile.bin");
      binfile.write((const char*)&sendValue,sizeof(int)); // write the adapted value
      

      std::ifstream binfile("binaryfile.bin");
      int recvValue = 0;
      binfile.read((char*)&recvValue,sizeof(int)); // read the value in network byte order
      int i = ntohl(recvValue); // convert the value of recvValue to host byte order
      

        

      &#34;那么这些小端和大端的用途是什么?&#34;

      不同格式的原因(使用)是,有不同的CPU架构,它们使用不同的方式在内存中表示整数值,具体取决于访问它们的特定硬件设计的最有效方式。
      这些架构差异并没有更糟/更好,这就是为什么它被称为 endianess 。这个造币的起源来自Johnatan Swift的小说&#34; Gulliver's travels&#34; 并且是Daniel Cohen的文章中提到的第一个(?) "ON HOLY WARS AND A PLEA FOR PEACE"


        

      &#34;编译器将自行完成,如果int i = 10 in little endian,那么在big endian中它也是10作为输出&#34;

      好吧,正如你从上面的例子中看到的那样,答案是错误的。

答案 3 :(得分:1)

在以下情况下,字节顺序很重要:

  1. 您正在直接检查/操作多字节类型的字节
  2. 您正在序列化二进制数据,或在不同架构之间传输二进制数据
  3. 直接检查/操作多字节类型中的字节

    例如,假设您要拆分并显示32位IEEE浮点的二进制表示。下面显示了float和big-little-endian体系结构中float的布局和相应字节的地址:

    A        A+1      A+2      A+3        Big endian
    -------- -------- -------- --------   s = sign bit
    seeeeeee efffffff ffffffff ffffffff   e = exponent bit
    -------- -------- -------- --------   f = fraction bit
    A+3      A+2      A+1      A          Little Endian
    -------- -------- -------- --------
    A+1      A        A+3      A+2        "Middle" Endian (VAX)
    

    符号位在float的最高有效字节(MSB)中。在大端系统上,MSB是字节A;在小端系统上,它在字节A + 3中。在像旧的VAX F浮点数这样的奇怪的球上,它被卡在中间的A+1字节处。

    因此,如果你想掩盖符号位,你可以执行以下操作:

    float val = some_value();
    unsigned char *p = (unsigned char *) &val; // treat val as an array of unsigned char
    
    // Assume big-endian to begin with
    int idx = 0;
    
    if ( little_endian() )
      idx = 3;
    
    int sign = (p[idx] & 0x80) >> 7
    

    序列化或传输二进制数据

    再例如,您希望保存二进制(非文本)数据,以便大端或小端系统可以读取数据,或者将二进制数据从一个系统传输到另一个系统。互联网传输的惯例是big-endian(MSB优先),因此在通过'net发送消息之前,您使用htonl(主机到网络长)和htons等呼叫(主机到网络短路)在发送数据之前执行任何必要的字节交换:

    uint32_t host_value = some_value();
    uint32_t network_value = htonl( host_value ); 
    send( sock, &network_value, sizeof network_value, 0 ); 
    

    在像x86这样的小端系统上,htonl会将host_value的字节从0,1,2,3重新排序到3,2,1,0并将结果保存到{{ 1}}。在大端系统上,network_value基本上是无操作系统。逆操作是htonlntohl

    如果您做上述事情,那么您通常不必担心字节序。