在 Big Endian 和 Little Endian 机器中解释 32 位整数的混淆
Confusion in interpreting 32 bit integer in Big Endian and Little Endian Machines
我正在将代码从大端机重写到小端机。
假设有一个名为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()
吗?
你应该使用 htonl()
。在大端机器上这什么都不做,它只是 returns 原始值。在小端机器上,它适当地交换字节。所以通过使用它,你不必关心机器的字节顺序,你可以在调用它之后使用相同的代码。
您最初编写的代码将在大端和小端机器上执行您想要的操作。
如果 a
的值为 0x00123456
,则 0x12
进入 arr[0]
,0x34
进入 arr[1]
, 0x56
进入 arr[2]
。无论机器的字节顺序如何,都会发生这种情况。
当您使用 >>
和 &
运算符时,它们对相关表达式的 value 进行运算,而不是 该值的表示。
当您调用 htonl
时,您更改值以匹配特定表示。所以在小端机器上 htonl(0x00123456)
将产生值 0x56341200
。然后,当您对该值进行操作时,您会得到不同的结果。
当使用多个字节表示的数字以字节形式读取或写入时,即通过网络写入磁盘或 to/from 字节缓冲区时,字节序很重要。
例如,如果您这样做:
uint32_t a = 0x12345678;
...
write(fd, &a, sizeof(a));
然后 a
组成的四个字节一次一个地写入文件描述符(无论是文件还是套接字)。大端机器将按 0x12
、0x34
、0x56
、0x78
顺序写入,而小端机器将写入 0x78
、0x56
, 0x34
, 0x12
。
如果您希望以一致的顺序写入字节,那么您应该先调用 a = htonl(a)
,然后再调用 write
。那么字节总是写成0x12
, 0x34
, 0x56
, 0x78
.
因为您的代码对值而不是值的各个字节进行操作,所以您无需担心字节序。
我正在将代码从大端机重写到小端机。
假设有一个名为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()
吗?
你应该使用 htonl()
。在大端机器上这什么都不做,它只是 returns 原始值。在小端机器上,它适当地交换字节。所以通过使用它,你不必关心机器的字节顺序,你可以在调用它之后使用相同的代码。
您最初编写的代码将在大端和小端机器上执行您想要的操作。
如果 a
的值为 0x00123456
,则 0x12
进入 arr[0]
,0x34
进入 arr[1]
, 0x56
进入 arr[2]
。无论机器的字节顺序如何,都会发生这种情况。
当您使用 >>
和 &
运算符时,它们对相关表达式的 value 进行运算,而不是 该值的表示。
当您调用 htonl
时,您更改值以匹配特定表示。所以在小端机器上 htonl(0x00123456)
将产生值 0x56341200
。然后,当您对该值进行操作时,您会得到不同的结果。
当使用多个字节表示的数字以字节形式读取或写入时,即通过网络写入磁盘或 to/from 字节缓冲区时,字节序很重要。
例如,如果您这样做:
uint32_t a = 0x12345678;
...
write(fd, &a, sizeof(a));
然后 a
组成的四个字节一次一个地写入文件描述符(无论是文件还是套接字)。大端机器将按 0x12
、0x34
、0x56
、0x78
顺序写入,而小端机器将写入 0x78
、0x56
, 0x34
, 0x12
。
如果您希望以一致的顺序写入字节,那么您应该先调用 a = htonl(a)
,然后再调用 write
。那么字节总是写成0x12
, 0x34
, 0x56
, 0x78
.
因为您的代码对值而不是值的各个字节进行操作,所以您无需担心字节序。