在下面的示例中,我使用两个结构体test1
和test2
来说明这一点。第一个结构体有两个元素——一个大小为2的整数数组和一个浮点元素。第二个结构体有3个元素,2个整数和1个浮点数。
我将test1的两个结构变量s1和s2初始化为:
s1={{23,52},2.5},s2={21,19,3.6};
都可以正常工作,即使对于s2,我已经去掉了括住数组元素的大括号。它工作正常,没有警告,输出是正确的。但是当我为初始化两个变量时,test2如下所示:
v1={{23,52},2.5},v2={21,19,3.6};
当我试图打印出v1的值时,我得到了不正确的输出,这些是我在编译时得到的警告:
warning: braces around scalar initializer|
warning: (near initialization for 'v1.list1')|
warning: excess elements in scalar initializer|
warning: (near initialization for 'v1.list1')|
||=== Build finished: 0 errors, 4 warnings ===|
基于此前提,请澄清以下产生的疑问:
问题:如果使用v1={{23,52},2.5}
代替v1={23,52,2.5}
会使编译器混淆前2个数字是结构体的不同整数元素还是结构体的整数数组元素的一部分,那么为什么使用s2={21,19,3.6}
代替s2={{21,19},3.6}
不会使编译器混淆认为结构变量s2有3个元素(2个整数元素和一个浮点数),而不是2个元素(一个大小为2的整数数组和一个浮点数)?我特别想理解的是为什么第一个关于v1的初始化是错误的。
#include<stdio.h>
struct test1{
int list[2];
float rate;
}s1={{23,52},2.5},s2={21,19,3.6}; //Works fine
struct test2{
int list1;
int list2;
float rate;
}v1={{23,52},2.5},v2={21,19,3.6}; //Messes things up
int main(void)
{
printf("%d,%d,%fn",s1.list[1],s2.list[1],s2.rate);
printf("%d,%d,%fn",v1.list1,v1.list2,v1.rate);
}
这只是初始化器规则定义方式的结果。如果初始化的当前对象是struct
、union
或数组,那么如果下一个初始化项以{
开头,则用大括号括起来的初始化项及其匹配的}
来初始化该对象的成员;否则,它只是遍历初始化器列表,需要多少就取多少。
所以,在第一种情况下s1={{23,52},2.5}
,当前对象开始为s1.list
。这是一个数组,下一个初始化器是{ 23, 52 }
,因此它用于初始化数组。s1.rate
现在是当前对象,下一个初始化器是2.5
,所以它可以正常工作。
在第二种情况s2={21,19,3.6}
中,当前对象从s2.list
开始。这是一个数组,但是下一个初始化器没有从{
开始-所以它需要多少值就取多少值(在本例中是两个),并使用21
和19
初始化数组。s2.rate
现在是当前对象,而下一个初始化器是2.5
,所以再次按预期工作。
在第三种情况v1={{23,52},2.5}
中,当前对象从v1.list1
开始。这是一个标量,对应的初始化式是{23, 52}
。这违反了语言的约束——"标量的初始化式必须是单个表达式,可选地用大括号括起来"——这就是您得到警告的原因。形式上,程序的行为是未定义的,但似乎编译器只使用初始化器中包含的第一个值,并丢弃多余的值。当前对象现在是v1.list2
,下一个初始化器是2.5
,因此使用错误的值来初始化该成员。没有v1.rate
的初始化式;由于v1
具有静态存储持续时间,因此该成员是0.0
的初始化项。
在第四种情况v2={21,19,3.6}
中,当前对象以v1.list1
开始,下一个初始化项是21
——该值用于初始化成员。在此之后,当前对象是v1.list2
,下一个初始化项是19
;那么v1.rate
是当前对象,下一个初始化项是3.6
。
为减少混淆,您应该始终为每个struct
或数组子对象使用大括号括起来的初始化项。
在变量s2
的情况下,编译器知道嵌入数组的大小,因此即使没有括号,它也可以正确地分配给它。然而,你可能会得到一个警告,建议你使用括号,如果你不这样做,那么我建议你启用更多的编译器警告(这是很好的修复警告,因为它们可能指示错误,可能是有效的C,但无效的逻辑)。
在v1
的情况下,你不能使用额外的括号,因为没有复合数据类型(结构/联合/数组)。括号{}
只能用于初始化复合数据类型。