3

在下面的示例中,我使用两个结构test1和来说明这一点test2。第一个有两个元素 - 一个大小为 2 的整数数组和一个浮点元素。第二个结构有 3 个元素,2 个整数和一个浮点数。

我将test1的两个结构变量s1s2初始化为:

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}让编译器混淆前2个数字是结构的不同整数元素还是结构的整数数组元素的一部分,那么为什么不使用s2={21,19,3.6}而不是s2={{21,19},3.6}让编译器认为结构变量s23 个元素(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,%f\n",s1.list[1],s2.list[1],s2.rate);
    printf("%d,%d,%f\n",v1.list1,v1.list2,v1.rate);
}
4

2 回答 2

4

这只是如何定义初始化程序规则的结果。如果初始化的当前对象是 a或数组structunion那么如果下一个初始化器以 a 开头,{则该大括号括起来的初始化器及其匹配}用于初始化该对象的成员;否则,它只会遍历初始化程序列表,并根据需要获取尽可能多的信息。

因此,在第一种情况下s1={{23,52},2.5},当前对象以 开始s1.list。这是一个数组,下一个初始化程序是{ 23, 52 },因此用于初始化数组。 s1.rate现在是当前对象,下一个初始化程序是2.5,因此可以按预期工作。

在第二种情况下s2={21,19,3.6},当前对象以s2.list. 这是一个数组,但下一个初始化程序不是以 - 开头的,{因此它需要尽可能多的值(在本例中为两个),并使用 和 初始化21数组19s2.rate现在是当前对象,下一个初始化程序是2.5,所以再次按预期工作。

在第三种情况下v1={{23,52},2.5},当前对象以v1.list1. 这是一个标量,对应的初始化程序是{23, 52}. 这违反了语言的约束—— “标量的初始化程序应该是一个表达式,可选地用大括号括起来”——这就是你收到警告的原因。正式地,您的程序的行为是未定义的,但您的编译器似乎只使用初始化程序中包含的第一个值并丢弃多余的值。当前对象是 now v1.list2,下一个初始化器是2.5,所以使用了错误的值来初始化这个成员。没有初始化器v1.rate;由于v1具有静态存储持续时间,因此该成员初始化为0.0.

在第四种情况下v2={21,19,3.6},当前对象以 开始v1.list1,下一个初始化器是21- 此值用于初始化成员。在此之后,当前对象是v1.list2,下一个初始化器是19;thenv1.rate是当前对象,下一个初始化程序是3.6.

struct为了尽量减少混淆,您应该始终为每个子对象或数组子对象使用大括号括起来的初始化程序。

于 2013-05-13T04:56:43.883 回答
0

在变量 的情况下s2,编译器知道嵌入数组的大小,因此即使没有括号,它也可以正确分配给它。但是,您可能会收到一条警告,建议您使用括号,如果您不这样做,那么我建议您启用更多编译器警告(修复警告很好,因为它们可能表明错误可能是有效的 C 但无效的逻辑)。

在这种情况下v1,您不能使用额外的括号,因为没有复合数据类型(结构/联合/数组)。大括号{}只能用于初始化复合数据类型。

于 2013-05-13T07:43:23.343 回答