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”?
使用 {}
和 ()
有什么区别?
{}
表示初始化一个子对象。
()
是用于对表达式进行分组的运算符,例如 (1+3)*2
。你混淆了逗号运算符,逗号运算符会丢弃其左操作数并返回右操作数。 (12,1)
等同于 1
。
初始化一个 union
总是设置它的第一个成员并忽略其他成员。这是因为一次只能有一个成员存储值。
将标量值用于数组子对象的初始化,例如将 1
传递给 c[2]
进行初始化,会自动跳转到数组中。这被称为花括号省略。下一个 1
将初始化数组的第二个成员。
你将 1
分配给 c[2]
中的每个字符,然后将结果字节串作为小端 int
读回。数组 ch[2]
没有被显式初始化,在 C++ 中它将被设置为零,但我不确定在 C 中是否也是如此。
初始化程序 {{12, 1}, {15, 1}}
无法工作,因为花括号省略将第一个 }
解释为关闭整个 union
。
初始化程序 {{{12, 1}, {15, 1}}}
将避免花括号省略并设置两个数组。 {12, 1, 15, 1}
应该也会达到同样的效果。
请注意,标量值和字节串之间的转换是实现定义的;特别是它取决于大小端和 int
的大小。
两个元组 (12, 1)
和 (15, 1)
奇怪的是都简化为了 1
。这是因为,正如 Omkant 所说,您正在使用逗号运算符,它执行它分隔的每个表达式,但返回最后一个表达式的值。实际上,维基百科条目 很好地解释了这一点。
结果是,u.s.c[0]
被填充了第一个 1,而 u.s.c[1]
被填充了第二个 1。由于联合将 int u.st.i
叠加在 u.c[2]
和 u.ch[2]
上(假设 8 位字符和 32 位的 int),并且架构是小端的(从您的结果中可以得知),因此 u.st.i
的最低字节中有一个 1,并且在其第二低字节中有一个 1,总共的值为 256*1 + 1 = 257
。
同时,没有值写入到 u.st.j
的内存中,因此第二个输出为 0。
what the difference will it create if i use {} instead of ().
()
,那么,
将是逗号运算符
,并且分配的值将是括号内最右边的值。{}
的情况下,,
是逗号分隔符
,每个单独的值都分配给相应的成员。但在这种情况下,它不会编译并会抛出错误:初始化器末尾有多余的花括号组。
看起来你误解了联合的作用,联合中的对象共享它们的内存,因此你只能初始化其中一个对象而不能同时初始化两个对象。换句话说,底层内存是相同的。正如其他答案中提到的,初始化联合总是设置其第一个成员,如果你想初始化第二个成员,可以使用C99指定的初始化器:
u = {.st={15, 1} };
而要初始化第一个结构中的数组:
u = { .s={{12, 1}, {15, 1}} };
或者对于第一个结构体,不使用.s
:
u = { {{12, 1}, {15, 1}} };
{{12, 1},{15, 1}}
在使用gcc -std=c99编译时会出现错误:初始化器末尾有额外的花括号组。 - iabdalkader