struct
{
int a[2], b;
}
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
如何在C语言中评估此行代码?结构体的一般声明与此语句不同。在C中访问元素可以像
[0].a
,[0].b
这样进行。struct
{
int a[2], b;
}
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
[0].a
,[0].b
这样进行。首先定义一个新的结构类型:
struct {
int a[2], b;
}
a
的包含两个 int
元素的数组和一个名为 b
的 int
变量。arr[]
这段代码定义了一个变量arr
,它是一个结构体数组。数组的大小没有被明确指定,因为变量是通过初始化来赋值(因此其大小由此初始化定义):
{ [0].a = ... }
由于你正在初始化某些东西,因此定义了你正在初始化的上下文(具有两个成员的结构数组)。然后,符号[0]
只引用数组的第一个成员(所以数组至少有一个元素),由于该元素是结构化的,则[0].a
表示其成员a
,本身就是一个数组。然后,这个数组也通过{1}
进行了初始化。这里的技巧是,这个数组成员的长度已经由类型定义确定:长度为2,那么{1}
将该数组的第一个元素初始化为1,第二个元素初始化为0
(int的默认初始化值)。等等。
最终:
{[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
将 arr
初始化为:
a
初始化为 1,0,其成员 b
初始化为 1a
初始化为 2,0,并且其成员 b
初始化为 2如果您使用赋值语句,则可以编写类似以下内容的代码:
struct { ... } arr[2];
arr[0].a[0] = 1;
arr[0].a[1] = 0;
arr[0].b = 1;
arr[1].a[0] = 2;
arr[1].a[1] = 0;
arr[1].b = 2;
在IT技术中,[0]
(例如)表示数组的第一个元素,但是需要用表示该数组的表达式作为前缀,因此是arr[0]
...
=
的内容是一个初始化器而不是表达式。在初始化器中可以做的事情与表达式中可以做的不同。struct {int a[2], b;} arr[];
arr[0].a = {1};
arr[1].a = {2};
arr[0].b = 1;
arr[1].b = 2;
数组arr
的长度为2,因为提供了两个元素的值。 arr [0]
从传统上写为{{1},1}
进行初始化。arr [1]
从{{2},2}
初始化。
在C语言中,也可以像这样访问元素:
[0].a
,[0].b
吗?
简而言之:只有当你编写指定初始化器时才能这样做。
designator:
[ constant-expression ]
. identifier
因此,在你的情况下,
struct
{
int a[2], b;
}
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
arr
,并提供这些单独元素成员的初始值。1
,因此数组arr
的大小为2(基于0的索引)。[0].a = {1}
试图将arr[0]
元素的成员a
的值初始化为1
。这等效于arr[0].a[0]
。对于所有其余情况也是如此。a[0]
和a[1]
的值。在这里,由于“部分初始化”(花括号包含的初始化器未提供数组中所有成员的初始值),arr[0].a[0]
设置为1
,而arr[0].a[1]
设置为0
。(注2)
注意1:
引用《C11》,第§6.7.9/P22章节
如果初始化大小未知的数组,则其大小由具有显式初始化器的最大索引元素确定。数组类型在其初始化器列表结束时完成。
注意2:
引用《C11》,第§6.7.9/P21章节(我强调)
如果花括号包围的列表中的初始化程序少于聚合体的元素或成员,或者用于初始化已知大小的数组的字符串字面量中的字符数少于数组中的元素数,则聚合体的其余部分应隐式初始化为具有静态存储期的对象相同。
第一部分是定义一个结构体变量。通常你会看到这样的代码:
// define the type
struct foo { ... };
// define a variable of that type
struct foo x;
但是你可以将两者结合起来:
// define a type and a variable of that type
struct foo { ... } x;
// define a variable of an unnamed struct type
struct { ... } x;
struct { int a[2], b; }
,因此我们处理具有两个成员的未命名结构体,一个名为a
的2个int数组和一个名为b
的int。arr
。名称后面的[]
表示我们将其定义为数组。// define an array of 2 elements
int arr[2];
// define and initialize an array of 2 elements
int arr[2] = { 100, 200 };
使用初始化程序,我们不必明确说明数组的大小;它可以从初始化程序中推断出来:
// define and initialize an array of 2 elements
int arr[] = { 100, 200 };
将这应用到您的情况中,您可能会看到类似以下内容:
struct { int a[2], b; } arr[] = { { {1}, 1 }, { {2}, 2 } };
// ^a^ ^a^
// ^^struct^^ ^^struct^^
int a[2]
) 中嵌套了一个结构体,而这个结构体又嵌套在一个数组 (arr[]
) 中。如果你想知道 a
的第二个元素发生了什么:当一个变量只被部分初始化时,所有剩余的部分都会被设置为 0
。所以这段代码实际上将内部数组初始化为 {1, 0}
和 {2, 0}
。[
]
) 或者是一个点号后跟成员名称。指定符也可以链接在一起:[0].b = 42
表示“将此数组的第 0
个元素的成员 b
初始化为 42”。struct { int a[2], b; } arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
如果我们按照索引重新排序初始化器,我们会得到:
struct { int a[2], b; } arr[] = {[0].a = {1}, [0].b = 1, [1].a = {2}, [1].b = 2};
struct { int a[2], b; } arr[] = {[0] = { .a = {1}, .b = 1 }, [1] = {.a = {2}, .b = 2} };
arr
的大小为2),以及这些值实际上是什么。struct { int a[2], b; } arr[] = { { {1}, 1 }, { {2}, 2 } };
[0].a
,[0].b
是 C99
语法。=
前使用 [index]
和 .fieldname
标识符来指定要初始化的嵌套子对象,该列表相对于与最近的大括号对应的子对象进行解释。发布的代码存在一些错误的初始化语法。
我在Ubuntu Linux 16.04上使用了gcc
编译器。
编译器输出以下信息:
warning: missing initializer for field 'b' of 'struct <anonymous>' [-Wmissing-field-initializers]
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};
note: 'b' declared here
int a[2], b;
上述行重复了两次。
请更正语法并重新发布。
arr
的初始化。这只是在语句之后立即设置数组应包含的值。在这种情况下,使用了一种相对较新的语法,称为指定初始化程序,它是在C99标准中引入的,并仅在变量初始化期间使用(包括复合文字)。 - doynax[0].a
表示索引为0
的结构体并访问其属性a
。 - Rahularr[0].b = 1;
。 - M.Marr
:) - Sourav Ghoshstruct
命名一个标签名称。这样,通过gdb
等工具可以深入地显示该结构。 - user3629249