简体   繁体   English

C中的隐秘结构定义

[英]Cryptic struct definition in C

I came across the following maze definition code: 我遇到了以下迷宫定义代码:

typedef struct mazeNode {
    int hasCheese;
    int tag;
    struct mazeNode *left;
    struct mazeNode *right;
} maze_t;

maze_t maze = {
    .tag = 1,
    .left = &(maze_t) {
        .left = &(maze_t) {
            .left = &(maze_t) {},
            .right = &(maze_t) {}
        },
        .right = &(maze_t) {
            .right = &(maze_t) {}
        }
    },
    .right = &(maze_t) {
        .tag = 8,
        .left = &(maze_t) {},
        .right = &(maze_t) {
            .tag = 10,
            .left = &(maze_t) {
                .tag = 11,
                .left = &(maze_t) {
                    .hasCheese = 1,
                    .tag = 12
                }
            },
            .right = &(maze_t) {}
        }
    }
};

From the linked blog post I understand that they are trying to define the binary tree with the cheese in the diagram. 从链接的博客文章中我了解到他们正在尝试使用图中的奶酪来定义二叉树。

However I can't seem to make head or tail out of what the C code is supposed to do. 但是,我似乎无法克服C代码应该做的事情。 It would be great if someone could explain it to me. 如果有人能向我解释它会很棒。

This code is using a combination of designated initializers and compound literals , which are both C99 features , I linked to other answer where I provide standard quotes for both of these features. 此代码使用指定的初始化程序复合文字的组合,这两者都是C99功能 ,我链接到其他答案,我为这两个功能提供标准报价。

Designated initializers allow you to use specify a specific field to initialize using .fieldname = , an example from the linked document is: 指定的初始值设定项允许您使用.fieldname =指定特定字段进行初始化,链接文档中的示例如下:

  struct point { int x, y; }; 

the following initialization 以下初始化

 struct point p = { .y = yvalue, .x = xvalue }; 

is equivalent to 相当于

 struct point p = { xvalue, yvalue }; 

The other feature being used is compound literals which is being used to create unnamed static objects and then the code takes the address of this object and assigns it the respective pointers left and right . 所使用的其他特征是,其是被用来创建无名静态对象复合文字,然后将代码借此对象的地址和分配给它的相应指针leftright It then uses this feature recursively within the unnamed objects to set their respective left and right pointers. 然后,它使用此功能递归无名对象中设置各自的leftright指针。

 .left = & (maze_t) { .... }
           ^^^^^^^^^^^^^^^^
           unnamed static object

These unnamed objects are only static if they are used outside the body of a function otherwise they will have automatic storage duration and would cease to exist once you exit the function and so taking their addresses like the code is doing would probably be unwise. 这些未命名的对象只有在函数体外使用时才是静态的,否则它们将具有自动存储持续时间,并且一旦退出函数就会停止存在,因此像代码那样获取它们的地址可能是不明智的。

For reference I provide a standard quote on compound literals in my answer here . 作为参考,我在这里提供了关于复合文字的标准引用。

Important to note that when using designated initializers any field not explicitly initialized will be initialized to zero , which is actually important in this case, for example hasCheese will be set to 0 unless it is specifically set otherwise. 需要注意的是,当使用指定的初始化程序时,任何未明确初始化的字段都将初始化为零 ,这在这种情况下实际上很重要,例如hasCheese将设置为0除非另有特别设置。

Although these are C99 features not all compilers support or fully support C99, my tests on Visual Studio show that we need to replace the empty compound literals, for example: 虽然这些是C99功能并非所有编译器都支持或完全支持C99,但我对Visual Studio的测试表明我们需要替换空的复合文字,例如:

left = &(maze_t) {}

with a NULL to get it to compile. NULL来编译它。 I filed a bug report . 我提交了一份错误报告

The response to the bug report was as follows, but basically this is a gcc/clang extension at work: 对bug报告的响应如下,但基本上这是一个gcc / clang扩展工作:

This is a GNU extension. 这是一个GNU扩展。 Clang supports it as an extension (see the clang option -Wgnu-empty-initializer). Clang支持它作为扩展(参见clang选项-Wgnu-empty-initializer)。

The standard way to write this is {0}, which will zero initialize all fields. 写这个的标准方法是{0},它将零初始化所有字段。

The code is initializing a struct according to a syntax allowed in the C since 1999 (C99 and C11). 该代码根据自1999年以来C中允许的语法初始化结构(C99和C11)。

Briefly explained, you can initialize a struct variable by writting only the "members" of the struct enclosed in braces { }. 简要说明,您可以通过仅写入括号{}中包含的结构的“成员”来初始化结构变量。

For example, given the following struct: 例如,给定以下结构:

 struct fractional_number_s { int numerator; unsigned int denominator; };

we can define and initialize struct variables as follows: 我们可以定义和初始化struct变量,如下所示:

 struct fractional_number_s r = { .numerator = 3, .denominator = 7, };  

As you can see, it's enough to write the members, without the variable-name r . 正如您所看到的,编写成员就足够了,而没有变量名r
This syntax is allowed in initializers. 初始值设定项中允许使用此语法。

Also, in normal assignments we can have a similar syntax with the aid of compound literals , as in this example: 此外,在正常分配中,我们可以在复合文字的帮助下使用类似的语法,如下例所示:

 r = (struct fractional_numbers_s) { .numerator = 3, .denominator = 7 };  

Search on internet about these topics: C struct initializers and C compound literals , to obtain more information ( technical note: ANSI C89 doesn't have this syntax, so search for ISO C99 and ISO C11). 在互联网上搜索这些主题: C struct initializersC compound literals ,以获取更多信息( 技术说明: ANSI C89没有此语法,因此搜索ISO C99和ISO C11)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM