这段测试大字节序或小字节序的代码是如何工作的?
How does this code that tests for big- or little-endianness work?
我正在研究 Endianness,当我阅读一本教科书时,他们向我提供了这个 运行 时间测试来检查(在 运行 时间)代码是否 运行ning在小端或大端系统上。这本书没有解释任何东西,我很困惑这段代码是如何工作的。谁能帮我解释一下这段代码是如何工作的。提前谢谢你
/* Test platform Endianness */
int bigendian(void) {
int i;
union {
char Array[4];
long Chars;
} TestUnion;
char c = 'a';
for(i=0; i<4; i++)
TestUnion.Array[i] = c++;
if (TestUnion.Chars == 0x61626364)
return 1;
else
return 0;
}
假设您正在使用 ASCII 作为其字符集的系统,值 0x61
、0x62
、0x63
和 0x64
代表字母a
、b
、c
和 d
。
循环:
char c = 'a';
for(i=0; i<4; i++)
TestUnion.Array[i] = c++;
用 a
、b
、c
和 d
填充并集 TestUnion
的 char array
部分。如果您在 big-endian 机器上访问联合作为 32 位 long
,它将表示为 0x61626364
;如果它是 little-endian 多头将是 0x64636261
.
不过,这不是一个很好的 "general case" 算法来测试字节顺序,因为:
- 并非所有系统都使用 ASCII 来表示字符
- 一个
long
不一定是4*sizeof(char)
字节宽
union
提供了数据的不同观点——这里的TestUnion
可以解释为:
- 一个
char[4]
数组,或者
- a
long
整数
for
循环将 TestUnion
填充为 char[4]
数组 - 请注意字符 a
具有 ASCII 代码 0x61
而 b
是0x62
等等。所以内存中填充了4个字节0x61
、0x62
、0x63
、0x64
,每个字节的地址位置都是升序排列的。
if
语句通过将 TestUnion
解释为 long
整数来检查它是否为 BigEndian。如果它是 BigEndian,那么 long
int 数字是从 left-to-right 中读取的,它转换为 0x61626364
。否则它是 LittleEndian,将从 right-to-left 读取,意思是 0x64636261
.
您可以使用以下代码检查系统中的该功能:
printf( "bigendian ? %s\n", bigendian() ? "true" : "false" );
字节顺序是指内存中是低字节先存还是高字节先存。小端机器先存储低字节,大端机器先存储高字节。如果整数有两个以上的字节,其他顺序也是可能的,但非常罕见。
代码所做的是设置联合,以便 char 数组和长整数共享相同的地址 space。然后它通过计算预期值来检查 long 的字节是哪一圈。由于许多原因,它写得不好。从技术上讲,写入联合的一个字段然后从另一个字段读取是未定义的行为。该代码假定 sizeof(long) == 4
,ASCII 是字符集,并且编译器将按预期处理联合。可能所有这些都会成立。他还将带符号的值与设置了高位的十六进制值进行比较——我认为这没问题,但这取决于 C 标准的细节。
更好的测试就是
int x = 0xFF;
unsigned char *test = (unsigned char *)&x;
if(test[sizeof(int)-1] == 0xFF)
/* big-endian */
if(test[sizeof(int)-1] == 0x00)
/* little-endian */
我正在研究 Endianness,当我阅读一本教科书时,他们向我提供了这个 运行 时间测试来检查(在 运行 时间)代码是否 运行ning在小端或大端系统上。这本书没有解释任何东西,我很困惑这段代码是如何工作的。谁能帮我解释一下这段代码是如何工作的。提前谢谢你
/* Test platform Endianness */
int bigendian(void) {
int i;
union {
char Array[4];
long Chars;
} TestUnion;
char c = 'a';
for(i=0; i<4; i++)
TestUnion.Array[i] = c++;
if (TestUnion.Chars == 0x61626364)
return 1;
else
return 0;
}
假设您正在使用 ASCII 作为其字符集的系统,值 0x61
、0x62
、0x63
和 0x64
代表字母a
、b
、c
和 d
。
循环:
char c = 'a';
for(i=0; i<4; i++)
TestUnion.Array[i] = c++;
用 a
、b
、c
和 d
填充并集 TestUnion
的 char array
部分。如果您在 big-endian 机器上访问联合作为 32 位 long
,它将表示为 0x61626364
;如果它是 little-endian 多头将是 0x64636261
.
不过,这不是一个很好的 "general case" 算法来测试字节顺序,因为:
- 并非所有系统都使用 ASCII 来表示字符
- 一个
long
不一定是4*sizeof(char)
字节宽
union
提供了数据的不同观点——这里的TestUnion
可以解释为:
- 一个
char[4]
数组,或者 - a
long
整数
for
循环将 TestUnion
填充为 char[4]
数组 - 请注意字符 a
具有 ASCII 代码 0x61
而 b
是0x62
等等。所以内存中填充了4个字节0x61
、0x62
、0x63
、0x64
,每个字节的地址位置都是升序排列的。
if
语句通过将 TestUnion
解释为 long
整数来检查它是否为 BigEndian。如果它是 BigEndian,那么 long
int 数字是从 left-to-right 中读取的,它转换为 0x61626364
。否则它是 LittleEndian,将从 right-to-left 读取,意思是 0x64636261
.
您可以使用以下代码检查系统中的该功能:
printf( "bigendian ? %s\n", bigendian() ? "true" : "false" );
字节顺序是指内存中是低字节先存还是高字节先存。小端机器先存储低字节,大端机器先存储高字节。如果整数有两个以上的字节,其他顺序也是可能的,但非常罕见。
代码所做的是设置联合,以便 char 数组和长整数共享相同的地址 space。然后它通过计算预期值来检查 long 的字节是哪一圈。由于许多原因,它写得不好。从技术上讲,写入联合的一个字段然后从另一个字段读取是未定义的行为。该代码假定 sizeof(long) == 4
,ASCII 是字符集,并且编译器将按预期处理联合。可能所有这些都会成立。他还将带符号的值与设置了高位的十六进制值进行比较——我认为这没问题,但这取决于 C 标准的细节。
更好的测试就是
int x = 0xFF;
unsigned char *test = (unsigned char *)&x;
if(test[sizeof(int)-1] == 0xFF)
/* big-endian */
if(test[sizeof(int)-1] == 0x00)
/* little-endian */