【问题标题】:Confusion in interpreting 32 bit integer in Big Endian and Little Endian Machines在 Big Endian 和 Little Endian 机器中解释 32 位整数的困惑
【发布时间】:2017-01-03 13:30:52
【问题描述】:

我正在将代码从 Big Endian Machine 重写为 Little Endian Machine。

假设有一个名为a的变量,它是一个保存当前时间戳(用户请求的当前时间戳)的32位整数。

在 Big Endian 机器中,现在的代码是这样的:

uint32 a = current_timestamp_of_user_request;
uint8 arr[3] = {0};
arr[0] = ((a >> (8 * 2)) & 0x000000FF); 
arr[1] = ((a >> (8 * 1)) & 0x000000FF);
arr[2] = ((a >> (8 * 0)) & 0x000000FF);

现在,当我为小端机器编写相同的逻辑时,我可以使用相同的代码(方法a),还是应该这样转换代码(我们称之为方法b)?

uint32 a = current_timestamp_of_user_request;
uint32 b = htonl(a);
uint8 arr[3] = {0};
arr[0] = ((b >> (8 * 2)) & 0x000000FF); 
arr[1] = ((b >> (8 * 1)) & 0x000000FF);
arr[2] = ((b >> (8 * 0)) & 0x000000FF);

我写了这个程序来验证:

#include<stdio.h>
#include<stdlib.h>


void main() {
    long int a = 3265973637;
    long int b = 0;
    int arr[3] = {0,0,0};

    arr[0] = ((a >> (8 * 2)) & 0x000000FF); 
    arr[1] = ((a >> (8 * 1)) & 0x000000FF);
    arr[2] = ((a >> (8 * 0)) & 0x000000FF);

    printf("arr[0] = %d\t arr[1] = %d\t arr[2] = %d\n", arr[0], arr[1],   arr[2]);

    b = htonl(a);

    arr[0] = ((b >> (8 * 2)) & 0x000000FF); 
    arr[1] = ((b >> (8 * 1)) & 0x000000FF);
    arr[2] = ((b >> (8 * 0)) & 0x000000FF);

    printf("After htonl:\n");
    printf("arr[0] = %d\t arr[1] = %d\t arr[2] = %d\n", arr[0], arr[1],   arr[2]);

}

结果:

Result with little endian machine:

bgl-srtg-lnx11: /scratch/nnandiga/test>./x86
arr[0] = 170     arr[1] = 205    arr[2] = 133
After htonl:
arr[0] = 205     arr[1] = 170    arr[2] = 194

Result with big endian machine:
arr[0] = 170     arr[1] = 205    arr[2] = 133
After htonl:
arr[0] = 170     arr[1] = 205    arr[2] = 133

看起来没有转换为大端顺序,相同的逻辑(没有htonl())在填充数组arr 时给出了准确的结果。现在,如果我希望数组在小端和大端机器中相同(小端结果应该与大端结果完全相同),您能否回答我是否应该使用htonl()

【问题讨论】:

  • 如果目标是将时间戳的最低有效字节放入arr[2],那么两台机器上的代码应该相同。代码中的移位和屏蔽操作不依赖于字节序。

标签: c++ c endianness


【解决方案1】:

您最初编写的代码将在大端和小端机器上执行您想要的操作。

例如,如果a 的值为0x00123456,则0x12 进入arr[0]0x34 进入arr[1]0x56 进入arr[2]。无论机器的字节序是什么,都会发生这种情况。

当您使用&gt;&gt;&amp; 运算符时,它们对相关表达式的 进行操作,而不是该值的表示。 p>

当您调用htonl 时,您更改值以匹配特定表示。所以在小端机器上htonl(0x00123456) 将产生值0x56341200。然后,当您对该值进行操作时,您会得到不同的结果。

字节序很重要,当使用多个字节表示的数字以字节形式读取或写入时,即写入磁盘、通过网络或写入/来自字节缓冲区。

例如,如果你这样做:

uint32_t a = 0x12345678;
...
write(fd, &a, sizeof(a));

然后,a 包含的四个字节一次一个地写入文件描述符(无论是文件还是套接字)。大端机器将按此顺序写入0x120x340x560x78,而小端机器将写入0x780x560x340x12

如果您希望字节以一致的顺序写入,那么您应先调用a = htonl(a),然后再调用write。然后字节将始终写为0x120x340x560x78

因为您的代码对值而不是值的单个字节进行操作,所以您无需担心字节顺序。

【讨论】:

    【解决方案2】:

    您应该使用htonl()。在大端机器上,这什么也不做,它只是返回原始值。在小端机器上,它会适当地交换字节。所以通过使用这个,你不必关心机器的字节顺序,你可以在调用它之后使用相同的代码。

    【讨论】:

    • c++ 也是一样,所以我回滚了你的第一次编辑。
    • 他的代码使用printf()而不是cout,所以看起来像C。但是你说得对,问题的相关部分对于大多数C方言都是相同的。
    • 虽然c++的解决方案是一样的。
    • 但是如果你看到结果,对于没有 htonl() 的相同逻辑,相同的变量给出的结果与大端机器的 arr[] 结果相同。这就是为什么我很困惑。
    • 提醒一下,htonl() 不是标准的。转换可以在 4 个语句中进行。
    猜你喜欢
    • 2019-06-30
    • 2018-05-15
    • 2020-12-01
    • 2022-06-10
    • 2012-10-09
    • 2010-10-16
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多