首页 文章

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

提问于
浏览
3

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

让我们把int i = 10它作为 00000000 00000000 00000000 00001010 存储在二进制文件中,如下所示: -

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

大端

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

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

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


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

编译器将自己做,如果int i = 10 in little endian,那么在big endian中它也是10作为输出

这个答案是否正确?

4 回答

  • 1
    00000000 | 00000000 | 00000000 | 00001010 // big    endian
    
    00001010 | 00000000 | 00000000 | 00000000 // little endian
    

    无论数据是以big endian还是little endian模式存储,大多数情况下,只有当你试图通过指针访问内存中较小部分的变量时才会很重要,就像试图通过a访问32位整数的最低有效字符一样指向字符的指针或带有字符数组的联合 . 另一个问题的例子是,如果您将文件中的数据直接读取到32位整数数组中,或者从32位整数数组中读取数据 . 文件中的数据通常也以小端或大端模式存储 .

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

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

    无论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

    只是为了校正整数图: 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中, Least Significant Byte (LSB)存储在最低内存地址中 .

    在big endian中, Most Significant Byte (MSB)存储在最低内存地址中 .

  • 4

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

    • 您正在直接检查/操作多字节类型的字节

    • 您正在序列化二进制数据,或在不同体系结构之间传输二进制数据

    Directly examining/manipulating bytes in a multi-byte type

    例如,假设您要拆分并显示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+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
    

    Serializing or transferring binary data

    再举一个例子,你想保存二进制(非文本)数据,以便它可以被大端或小端系统读取,或者你_1164199_ 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并将结果保存到 network_value . 在大端系统上, htonl 基本上是无操作系统 . 逆操作是 ntohlntohs .

    如果您没有做上述任何事情,那么您通常不必担心字节序 .

  • 1

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

    00000000 | 00000000 | 00000000 | 00001010 // big endian
    
    00001010 | 00000000 | 00000000 | 00000000 // little endian
    

    至于你的假设和问题:

    “在这既小又大endian会给出相同的输出10?“

    这取决于你所指的 kind of output .

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

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

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

    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
    

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

    不同格式的原因(使用)是,有不同的CPU架构,使用不同的方式在内存中表示整数值,这取决于访问它们的特定硬件设计的最有效方式 .
    有's no worse/better for these architectural differences, that'为什么它被称为endianess . 这个造币的起源来自Johnatan Swift的小说"Gulliver's travels",并且是Daniel Cohen的文章_1564221中提到的第一个(?) .


    “编译器将自己做,如果int i = 10 in little endian,那么在big endian中它也是10作为输出”

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

相关问题