C语言语句的求值

Evaluation of a statement in C language

struct 
{
    int a[2], b;
} 
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};

C语言如何对这一行求值? struct 的一般声明与此声明不同。也可以像 [0].a[0].b 这样的方式访问 C 中的元素?

这是声明,而不是语句,这就是为什么 = 后面是初始化程序,而不是表达式。您可以在初始化程序中执行的操作与您可以在表达式中执行的操作不同。

语法看起来与表达式中引用元素的方式相似。无效伪代码解释含义:

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}.

初始化

Also accessing of an element in C can be done like [0].a , [0].b like this?

TL;DR 仅当您正在编写 designated initializer.


这里有两件事,结构定义和初始化。

对于初始化部分,使用了指定的初始化器。它采用

的形式
designator:
[ constant-expression ]
. identifier

所以,在你的情况下,

struct 
{
    int a[2], b;
} 
arr[] = {[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};

指定的初始化器指示编译器创建一个包含两个结构元素的数组arr大小由提供的初始化器中的最大索引决定,注 1)和提供这些单独元素的成员的初始值。

因此,在您的情况下,最大索引为 1,因此数组 arr 大小为 2(从 0 开始的索引)。

可以说,[0].a = {1}试图将arr[0]处元素的成员a的值初始化为1。这是 "equivalent" 到 arr[0].a[0]。所有剩余的情况也是如此。

请注意,这是而不是设置a[0]a[1]的值。这里,由于"partial initialization" 注2(大括号括起来的初始化器不提供数组中所有成员的初始值),arr[0].a[0]设置为1 并且 arr[0].a[1] 设置为 0.


注一:

引用 C11,章节 §6.7.9/P22

If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. The array type is completed at the end of its initializer list.

注2:

引用 C11,章节 §6.7.9/P21(强调我的

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

第一行是新结构类型的定义:

struct {
   int a[2], b;
}

它声明了一个包含两个成员的结构:一个包含两个名为 aint 和一个 int b.

的数组

接下来可以分解如下,首先是变量:

arr[]

它定义了一个变量arr,它是一个结构数组。数组的大小未定义,因为变量是通过以下方式初始化的(因此它的大小由此初始化定义):

{ [0].a = ... }

这是一个新的 C(C99,不是很新...)语法来初始化结构化数据类型的内容:designated initializer

当您初始化某些东西时,您正在初始化的内容的上下文被定义(具有两个成员的结构数组)。然后符号 [0] 只引用数组的第一个成员(因此数组至少有一个元素),并且由于这个元素是结构化的 [0].a 表示它的成员 a,它本身就是一个数组。然后这个数组也被 { 1 } 初始化。这里的诀窍是这个数组成员的长度已经由类型定义定义:长度 2,然后 { 1 } 初始化该数组,第一个元素等于 1,第二个元素 0 (默认值用于整数的初始化)。等等

最后:

{[0].a = {1}, [1].a = {2}, [0].b = 1, [1].b = 2};

arr 初始化为:

  1. 一个长度为 2 的数组
  2. 它的第一个元素成员a初始化为1,0并且它的成员b初始化为1
  3. 其第二个元素成员a初始化为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;

其中 [0](例如)表示数组的第一个元素,但需要以表示该数组的表达式作为前缀,因此 arr[0]...

第一部分是定义一个结构变量。通常你会看到这样的代码:

// 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; },因此我们正在处理一个具有两个成员的未命名结构,一个由 2 个整数组成的数组,称为 a 和一个称为 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[]) 中的结构中。如果您想知道 a 的第二个元素发生了什么:当变量仅部分初始化时,所有剩余部分都设置为 0。所以这段代码实际上将内部数组初始化为 {1, 0}{2, 0}.

您实际代码中的初始值设定项看起来有点不同。它使用了 C99 中引入的一个特性,称为 "designated initializers"。使用普通的初始化程序,您必须按顺序列出值;在 C99 中,你可以在前面加上一个 "designator" 来说明值的去向。指示符可以是方括号中的数组索引 ([ ]) 或后跟成员名称的 .。指示符也可以链接起来:[0].b = 42 表示 "initialize member b of element 0 of this array to 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].bC99 语法。

= 之前的 [index].fieldname 指示符指定要初始化的嵌套子对象,该列表相对于与最近的周围大括号对对应的子对象。

参考这个 link.

发布的代码有一些不正确的初始化语法。

我在 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;

上面的行重复了两次。

请更正语法并重新发布