字节顺序测试:为啥以下代码有效?

Posted

技术标签:

【中文标题】字节顺序测试:为啥以下代码有效?【英文标题】:Testing for Endianness: Why does the following code work?字节顺序测试:为什么以下代码有效? 【发布时间】:2011-09-27 17:15:35 【问题描述】:

虽然我确实了解字节顺序,但我对以下代码的工作方式有点不清楚。我想这个问题不是关于字节序,而是关于 char * 指针和 int 如何工作,即类型转换。另外,如果变量word 不是short 而只是int,会有什么不同吗?谢谢!

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int byteOrder() 
    short int word = 0x0001;
    char * byte = (char *) &word;
    return (byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);

【问题讨论】:

在运行时测试字节序是没有意义的——你已经知道编译时的字节序了。 三元运算符没有意义,return byte[0];就足够了。 @Ben:上面的比较干净;它更明确,并且优雅地跟踪 #defines 值的变化。 @paul:不是便携式的。 @jdv:你当然可以——你可以使用编译器预定义的宏(例如_LITTLE_ENDIAN_),或者因为你,程序员,已经知道目标字节序,你可以定义自己的宏。不存在“可移植性”问题。 【参考方案1】:

这是一个可爱的小程序。您有一个单词被设置为十六进制文字 1。如果您有小端,当您将指针转换为 char 指针时,最低有效字节(在本例中为 0x01)将位于字节 [0]。因此,如果 0x01 位于偏移量 0,那么您知道它是小端序,否则如果 0x00 位于偏移量 0,则您知道最低有效字节存储在较高的内存位置(偏移量 1)。

注意:指针总是指向字/数据结构等的最低内存地址...

【讨论】:

【参考方案2】:

一个短整数由两个字节组成,在本例中为0x000x01。在小端系统上,小字节在前,所以在内存中它显示为0x01,然后是0x00。大端系统自然是颠倒的。这是小端系统上短整数的指针的样子:

----------------------- ----------------------- 
|   0x01   |   0x00   | |          |          | 
----------------------- ----------------------- 
   &word                  &word+1

另一方面,字符指针总是按顺序递增。因此,通过获取整数的第一个字节的地址并将其转换为char * 指针,您可以按内存顺序递增整数的每个字节。这是对应的图表:

------------ ------------ ------------ ------------ 
|   0x01   | |   0x00   | |          | |          | 
------------ ------------ ------------ ------------ 
   &byte       &byte+1      &byte+2      &byte+3

【讨论】:

这是类型双关语规则的一个例外。通过char * 指针访问任何数据类型都是有效的。 啊!当然。感谢@Oli 的更正。我删除了该部分。 @Oli 你有参考吗? @Maxpm:从这个开始:cellperformance.beyond3d.com/articles/2006/06/…;我会在一分钟内拿出准确的 C 标准报价... @Maxpm: C99, 6.5/7: “一个对象的存储值只能由具有以下类型之一的左值表达式访问:......字符类型。”【参考方案3】:

(char *)&word 指向word 的第一个(最低地址)char(字节)。如果你的系统是 little-endian,这将对应于0x01;如果是大端,则对应0x00

是的,无论wordshortint 还是long(只要它们的大小比char 大),这个测试都应该有效。

【讨论】:

【参考方案4】:

它告诉你short 的字节顺序。至少在某些机器上,short 正好是两个字节。它不一定告诉您intlong 的字节顺序,当然,当整数类型大于两个字节时,选择不是二进制的。

真正的问题是你为什么想知道。编写代码几乎总是更简单、更健壮,这样它就无关紧要了。 (也有例外,但它们几乎总是涉及非常低级的代码,无论如何只能在一个特定的硬件上运行。如果你对硬件足够了解,可以编写这种代码,你就会知道字节序。)

【讨论】:

【参考方案5】:

在考虑 big-endian 与 little-endian 时,我用来记住字节顺序的技巧是“名称应该相反”:

当您手写数字时,自然的做法是从左到右书写,从最高有效数字开始,以最低有效数字结束。在您的示例中,您首先写入最高有效字节(即 0),然后写入最低有效字节(即 1)。这就是大端的工作方式。当它将数据写入内存(增加字节地址)时,它以最不重要的字节结束 - “小”字节。所以,big-endian 实际上以小字节结束。

对于 little-endian 也是如此:它实际上以最重要的字节结束,即“大”字节。

您的源代码检查第一个字节(即 byte[0])是否是最重要的字节 (0),在这种情况下,它是“big-startian”或 little endian 字节顺序。

【讨论】:

以上是关于字节顺序测试:为啥以下代码有效?的主要内容,如果未能解决你的问题,请参考以下文章

字节序

大端模式与小端模式网络字节顺序与主机字节顺序

小端字节顺序(在C中)

为啥 Delphi IBX TWideMemoField 转换 UTF8 字符串中的字节顺序以及如何避免它?

大端字节顺序和小端字节顺序有啥区别

网络字节顺序字节序转换