确定C中的编译器是小端还是大端

时间:2016-05-09 14:50:05

标签: c endianness

有人能告诉我这个程序如何确定编译器是小端还是大端。

#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;

由于

3 个答案:

答案 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个成员; lungolongch是一个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

这是确定字节序的常用技巧,但严格来说,行为未定义;你不应该写一个工会的一个成员,并从另一个成员读。这种技术“有效”,因为任何多字节类型都可以干净地映射到charunsigned 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.