对于结构变量,为什么初始化器{21,19,3.6}与{{21,19},3.6}相同,但反之亦然?
在下面的例子中,我用两个结构test1
和test2
来说明这个。第一个有两个元素 – 一个大小为2的整数数组,和一个浮点元素。第二个结构有3个元素,2个整数和1个浮点数。
我为test1初始化了两个结构变量s1和s2 :
s1={{23,52},2.5},s2={21,19,3.6};
两者都工作正常,即使对于s2我已经取出括起数组元素的大括号。它没有警告工作正常,输出正确。但是当我为test2初始化2个变量时如下:
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}
会使编译器混淆前两个数字是结构的不同整数元素还是整数数组元素的一部分结构,那么为什么不使用s2={21,19,3.6}
而不是s2={{21,19},3.6}
混淆编译器认为结构varialbe s2有3个元素(2个整数元素和1个浮动),而不是2个元素(一个大小为2的整数数组和一个浮点数)?我特别想了解的是为什么关于v1的初始化的第一个案例是错误的。
#include 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,%f\n",s1.list[1],s2.list[1],s2.rate); printf("%d,%d,%f\n",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.rate
; 由于v1
具有静态存储持续时间,因此该成员的初始化为0.0
。
在v2={21,19,3.6}
情况下, v2={21,19,3.6}
,当前对象以v1.list1
,下一个初始化为21
– 该值用于初始化成员。 在此之后,当前对象是v1.list2
,下一个初始化器是19
; 然后v1.rate
是当前对象,下一个初始化程序是3.6
。
为了最小化混淆,您应该始终为每个struct
或数组子对象使用括号括起的初始化程序。
在变量s2
的情况下,编译器知道嵌入式数组的大小,因此即使没有括号,它也可以正确地分配给它。 然而,您可能会收到警告,建议您使用护腕,如果不这样,我建议您启用更多编译器警告(最好修复警告,因为它们可能表示可能是有效C但无效逻辑的错误)。
在v1
的情况下,您不能使用额外的支撑,因为没有复合数据类型(结构/联合/数组)。 括号{}
只能用于初始化复合数据类型。