14
int main()
{
  union {
    struct {
      char c[2];
      char ch[2]; 
    } s;
    struct {
       int i;
       int j; 
    } st;
  } u = { (12, 1), (15, 1) };

  printf("%d %d ", u.st.i, u.st.j);
}

上面怎么会打印“257 0”?

使用{}而不是创建什么区别()

4

4 回答 4

14

{}表示初始化子对象。

()是对表达式进行分组的运算符,例如(1+3)*2. 您混淆了逗号运算符的使用,它丢弃了左侧的操作数并返回了右侧的操作数。(12,1)是一样的1

初始化 aunion总是设置它的第一个成员并忽略其他成员。这是因为一次只有一个成员可以存储一个值。

使用标量值初始化数组子对象,就像传递1给 initialize一样c[2],会自动跳转到数组中。这称为大括号省略。接下来1将初始化数组的第二个成员。

您分配1给 中的每个字符c[2],然后将生成的字节字符串作为 little-endian 读回int。数组ch[2]根本没有显式初始化;在 C++ 中它会被设置为零,但我不完全确定在 C 中。

初始化程序{ {12, 1}, {15, 1} }不起作用,因为显然,大括号省略解释第一个}关闭整个union.

初始化程序{{ {12, 1}, {15, 1} }}将避免大括号省略并设置两个数组。{ 12, 1, 15, 1 }应该做同样的事情。

请注意,标量值和字节字符串之间的转换是实现定义的;特别是它取决于字节顺序和大小int

于 2012-12-19T08:07:28.957 回答
3

两者都(12, 1)简化(15, 1)为(奇怪的是)1。这是因为,正如 Omkant 所说,您使用的是逗号运算符,它执行它划分的每个表达式,但返回最终表达式的值。维基百科条目实际上很好地解释了这一点。

结果,u.s.c[0]第一个 1u.s.c[1]被填充,第二个 1 被填充。由于联合覆盖 intu.st.iu.c[2]u.ch[2]假设 8 位字符和 32 位整数),并且架构是 little-endian (从您的结果中知道),您在 的最低字节中有u.st.i一个 1,在它的第二低字节中有一个 1,其值为256*1 + 1 = 257.

同时,没有值写入 的内存u.st.j,因此第二个输出为 0。

于 2012-12-19T08:10:16.247 回答
0
what the difference will it create if i use {} instead of ().

如果您使用()then ,则分配的值,Comma operator是括号内最右边的值。

但在 is 的情况下{} ,Comma seperator每个单独的值都分配给相应的成员。但在这种情况下,它不会编译并抛出错误:

extra brace group at end of initializer.

于 2012-12-19T07:55:40.463 回答
0

似乎您误解了联合的意义,联合中的对象共享它们的内存,因此您只能初始化其中一个对象而不是两者,换句话说,底层内存是相同的,并且如另一个答案中所述,始终初始化联合设置它的第一个成员,所以如果你想初始化第二个成员,你可以使用 C99 指定的初始化器:

u = {.st={15, 1} };

并初始化第一个结构中的数组:

u = { .s={{12, 1}, {15, 1}} };

或者没有.s第一个结构:

u = { {{12, 1}, {15, 1}} };
于 2012-12-19T08:23:37.693 回答