对于下面的工会声明
union a
{
int i;
char ch[2];
};
union a u;
u.ch[0] = 3;
u.ch[1] = 2;
由于i
和ch
存储在同一位置,i
现在应该<binary rep. of 3>
与<binary rep. of 2>
连接。但是,它以相反的顺序存储。
printf("%d",i);
给出515。 为什么呢?
答案 0 :(得分:3)
因为您正在打印数字%d
。所以,你有:
u.ch[0] = 3;
二进制是
0000 0011 // 8bits, as char is 1B
然后你有
u.ch[1] = 2;
是
0000 0010 // 8bits, as char is 1B
并且“当你把2和2放在一起时”(:D)
00..00 0000 0010 0000 0011 // sizeof (int) * 8 bits
^^^^^^ ^^^^^^^^^ ^^^^^^^^^
//(sizeof(int)*8-16)bits this is the 2 this is the 3
在十进制中为515
对不起,我错过了“为什么”的部分。它是特定于平台的,你应该阅读Endianness并且更具体 - 关于Big-endian和Little-endian。文章中有一些例子。 提示:好像你有一台小端机器
好的,我在这里总结一下我的评论:数组保证存储在连续的内存中。 我们假设sizeof( int ) == 2
,以便于解释。所以,你有
u.ch[0] = 3;
u.ch[1] = 2;
这将首先存储3
,并在下一个字节中写入2
。所以,正如你(我猜)所期望的那样,记忆是:
0000 0011 0000 0010
^^^^3^^^^ ^^^^2^^^^
但请记住你使用union
!然后打印int
。所以,int
具有相同的位:
0000 0011 0000 0010
你的机器是小端,将其“翻译”为:
0000 0010 0000 0011 (reversed order of the bytes!)
哪个是515
答案 1 :(得分:2)
结果取决于您正在尝试编程的计算机的endianness。
在小型终端机器Intel i686上是515
:
$ uname -m
i686
$ ./a.out
515
并且在像Sparc这样的bin端机器上是770
:
$ uname -m
sun4v
$ ./a.out
770
这是因为endianess将确定ch[0]
是高阶字节(大端)还是低阶字节(小端)i
。
答案 2 :(得分:0)
它给出了515,因为这是未指定的行为。没有人知道你正在使用什么编译器,以及编译器如何处理联合,没有人能回答你的问题。
编译器可以在联合内的任何位置自由存储任意数量的填充字节,但第一个字节除外。
该程序只需要返回与上次访问联合相对应的结果。如果您通过char数组成员进行访问,则只保证对char数组的读访问权是可靠的。读int成员可以给你任何东西,你不知道是什么。
由于这是未指定的行为,编译器甚至不需要记录它将如何处理此类访问。如果你很幸运他们做到了。
编译器完全可以为这样的代码提供填充字节或垃圾值。