有人能告诉我这个程序如何确定编译器是小端还是大端。
#include <stdio.h>
#include <sys/types.h>
int main(void) {
union {
long lungo;
char ch[sizeof(long)];
} unione;
unione.lungo = 1;
if (unione.ch[sizeof(long)-1] == 0)
printf("little endian\n");
else
printf("big endian\n");
return (0);
}
特别是我不明白这部分程序的作用:
union {
long lungo;
char ch[sizeof(long)];
} unione;
由于
答案 0 :(得分:2)
union {
long lungo;
char ch[sizeof(long)];
} unione;
这是联盟。其成员占用相同的内存区域。写一个成员(在这种情况下是整数)是一个常见的技巧......
unione.lungo = 1;
...然后读回另一个(通常是一个char数组)......
if (unione.ch[sizeof(long)-1] == 0)
...得到前一种类型的字节表示。 (在这种情况下,整数的“第一个”字节,以确定存储在整数中的1
是否显示在其中(这会使它成为一个小端平台),或者不是(这将使它成为一个big-endian平台。注意@chux评论 - 其他形式的endianess do 存在,虽然它们非常罕见。
附录J.1将“存储在最后一个工会成员以外的工会成员的价值”指定为未指明。
附录J.3.13将“任何对象中的字节数,顺序和编码(未在本国际标准中明确规定)”指定为实现定义。
第6.2.6节(“类型表示”)指定“某些对象表示不需要表示对象类型的值。如果存储 对象的值具有这样的表示,并由没有字符类型的左值表达式读取,行为是未定义。“
所以,虽然不是未定义的行为,但这个结构是......让我们说,走近边线。 ; - )
答案 1 :(得分:0)
#define IS_BIG_ENDIAN (!*(unsigned char*)(void*)&(uint16_t){1})
, uint16_t
是一种很好的方法。但可能还有其他的#endianness&#34;可能会给你误报的计划。我不确定。在这一点上,我欢迎一个带有反例的downvote!
从技术上讲,使用&#34;联合技巧&#34;在C ++中是未定义的,尽管你将在C中使用它。
在C语言中通过(void*)
进行转换是多余的,但在C ++中技术上是必需的。
答案 2 :(得分:0)
联盟的所有成员占据相同的记忆,使得它们相互重叠;写一个联盟的一个成员会更新联盟的所有成员。
您已设置unione
来存储2个成员; lungo
是long
,ch
是一个char
数组,大小可以保存sizeof long
个字节(4或8个字节,具体取决于您的系统;对于此讨论,我们假设4个字节)。这两个成员都叠加在一起(它们占用相同的4个字节的内存)。
请记住,在大端系统上,多字节类型的最重要的字节将存储在地址A,最低有效字节将被存储地址A + 3。在小端系统上,该顺序是相反的;最低有效字节将存储在地址A,最高有效字节将存储在地址A + 3:
BE: A A+1 A+2 A+3 where A is arbitrary address
---- ---- ---- ----
lungo: 0x00 0x00 0x00 0x01
---- ---- ---- ----
LE: A+3 A+2 A+1 A
另一方面,数组总是被存储,以便a[0]
存储在地址A,a[1]
存储在A + 1,等等。所以如果我们看ch
关于大端和小端系统上的lungo
,我们看到以下内容:
BE: ch[0] ch[1] ch[2] ch[3]
----- ----- ----- -----
lungo: 0x00 0x00 0x00 0x01
----- ----- ----- -----
LE: ch[3] ch[2] ch[1] ch[0]
因此,在小端系统上,ch[0]
对应lungo
的最低有效字节,其中包含值0x01
。在大端系统上,ch[0]
对应lungo
的最重要字节,其中包含值0x00
。
这是确定字节序的常用技巧,但严格来说,行为未定义;你不应该写一个工会的一个成员,并从另一个成员读。这种技术“有效”,因为任何多字节类型都可以干净地映射到char
或unsigned char
的数组上,但它通常不能在两个多字节类型之间干净地应用。
没有100%可移植,符合标准的方式来确定系统的字节顺序,至少没有我所知道的。所有我认识的都涉及这样的技巧或某种类型的惩罚,比如
long l = 0x00010203;
char *c = (char *) &l;
if ( c[0] == 0x03 )
// little-endian
else if ( c[0] == 0x00 )
// big-endian
else
// something else
同样,这不是一个好习惯,可能是未定义的,但它对大多数情况“有效”。
大端和小端不是唯一可能的排序,并且在单个系统上可以进行多次排序。 VAXen通常是little-endian,除了32位浮点数,它们是“中端”并且布局为2301.