第一部分是定义一个结构变量。通常你会看到这样的代码:
// 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 个整数数组和一个名为 b 的整数。
我们声明的变量是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[]) 内的结构中。如果您想知道as 的第二个元素发生了什么:当变量仅部分初始化时,所有剩余部分都设置为0。所以这段代码真正将内部数组初始化为{1, 0} 和{2, 0}。
实际代码中的初始化程序看起来有点不同。它使用了 C99 中引入的一个特性,称为“指定初始化程序”。使用普通的初始化程序,您必须按顺序列出值;在 C99 中,您可以在前面加上一个“指示符”,说明值的去向。指示符可以是括号中的数组索引 ([ ]) 或 . 后跟成员名称。指示符也可以链接:[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 } };