简体   繁体   English

为什么允许命名嵌套结构?

[英]Why are named nested structure allowed?

I stumbled upon a very strange feature of C: you can declare a named structure inside another structure provided that declare a member variable of that type at the same time: 我偶然发现了C的一个非常奇怪的功能:您可以在另一个结构中声明一个命名结构,只要该结构同时声明该类型的成员变量:

struct Robot_st {
    int pos_x;
    int pos_y;
    struct BatteryStatus_st { /* <- named struct */
        int capacity;
        int load;
    } battery;
};

The inner structure becomes then available outside the structure as any other type, rendering strange code like this perfectly valid: 然后,内部结构可以像其他任何类型一样在结构外部使用,从而呈现出像这样完全有效的奇怪代码:

struct Robot_st my_robot = {2, 3, {200, 50}};
struct BatteryStatus_st battery_snapshot; /* <- use of inner struct */

memcpy(
    &battery_snapshot,
    &my_robot.battery,
    sizeof(struct BatteryStatus_st)
);

printf("robot position: %d,%d\n", my_robot.pos_x, my_robot.pos_y);
printf("battery load: %d%%\n", battery_snapshot.load);

Nesting unnamed structures feels right, because as you cannot access the type later, there is no confusion about the scope of the type. 嵌套未命名的结构感觉不错,因为以后您无法访问类型时,就不会对类型的范围感到困惑。 The above code is also not valid in C++, although the nested declaration is, because C++ understands it as a type in the namespace of the outer structure, so you need to access it using 上面的代码在C ++中也是无效的,尽管嵌套声明是有效的,因为C ++将其理解为外部结构名称空间中的类型,因此您需要使用

struct Robot_st::BatteryStatus_st battery_snapshot;

which, despite feeling strange to declare both a type and a member at the same time, makes more sense. 尽管同时声明一个类型和一个成员感到很奇怪,但这更有意义。

So why is this construct valid in C? 那么,为什么这种构造在C语言中有效呢? Is there any history/reason behind? 背后是否有任何历史/原因? Is there a use case for such a construct? 有这种结构的用例吗? (Mine was a mistake that led to failures, thus the question.) (我的错误是导致失败的错误,因此是问题。)

Link to full working code . 链接到完整的工作代码

In addition to the other two answers, here is a real usecase that calls for such a named inner struct: 除了其他两个答案,这是一个真正的用例,它需要这样的命名内部结构:

struct LinkedList {
    //data members stored once per list
    struct LinkedListNode {
        //data members for each entry of the list
        struct LinkedListNode *next;
    } *head, *tail;
};

Its hard to write a more concise definition for the structure of a linked list. 很难为链接列表的结构写出更简洁的定义。

An unnamed inner struct won't do: The code that inserts something into the linked list will likely have to declare local variables with node pointers. 无法命名的内部结构将无法使用:将某些内容插入链表的代码可能必须使用节点指针声明局部变量。 And there is no point in declaring the node structure outside of the linked list structure. 而且,在链表结构之外声明节点结构毫无意义。

Such constructs were allowed in C originally because structure names occupied a universe all their own which never had any sort of scoping rules applied to it [struct member names did too, by the way, which is why some of the structure types in older standard libraries have prefixes on their members]. 最初在C中允许使用此类构造,因为结构名称完全占据了自己的整个Universe,从来没有对其应用任何范围界定规则[顺便说一下,结构成员名称也具有这种作用域,这就是为什么旧标准库中的某些结构类型的原因其成员上带有前缀]。 Because some code exists which uses structure names in a fashion inconsistent with scoping, the standard could not be changed to prohibit such usage without breaking existing code. 因为存在一些代码,它们以与作用域不一致的方式使用结构名称,所以在不破坏现有代码的情况下,无法更改标准以禁止这种用法。 While there are times when it's worthwhile to break existing code (eg to rid C of the abomination called gets ) this really isn't one of them. 虽然有时候值得破坏现有代码(例如,摆脱C语言称为gets的可憎性),但这确实不是其中之一。

Let's say I have this structure: 假设我具有以下结构:

struct OuterStruct
{
    int a;
    struct InnerStruct
    {
        int i;
        int j;
    } b;
} s;

Now I can access sa , and I can even save it in a variable, to better handle it, pass it to functions, ... 现在,我可以访问sa ,甚至可以将其保存在变量中,以更好地处理它,并将其传递给函数,...

int sa = s.a;

Well, now I want to do the same with sb , and to do so I need InnerStruct to have a name! 好吧,现在我想对sb进行同样的操作,为此,我需要InnerStruct来命名!

???? sb = s.b;   // here I have to use InnerStruct, otherwise sb would have no valid type!

The alternative would be to declare InnerStruct outside of OuterStruct , and then putting an instance of it inside as member of OuterStruct . 另一种方法是申报InnerStruct以外OuterStruct ,然后把它的一个实例内作为构件OuterStruct But this would hide the fact that InnerStruct belongs to OuterStruct , making your intent less clear. 但这掩盖了InnerStruct属于OuterStruct的事实,使您的意图不太清楚。

Well, this is legal in C: 好吧,这在C语言中是合法的:

struct BatteryStatus_st {
    int capacity;
    int load;
};

struct Robot_st {
    int pos_x;
    int pos_y;
    struct BatteryStatus_st battery;
};

and, as you pointed out, it is effectively identical to the code you posted (since C doesn't have the namespace/scoping rules introduced in C++). 并且,正如您所指出的,它实际上与您发布的代码相同(因为C没有C ++中引入的名称空间/作用域规则)。

If moving the "inner" type inside doesn't change anything, but may sometimes clarify intent, it would seem odd to prohibit it. 如果将“内部”类型移入内部不会改变任何东西,但是有时可以澄清意图,则禁止它似乎很奇怪。

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

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