C 语言中结构体相互嵌套有什么优点吗

2019-01-10 13:22:19 +08:00
 cwx391497

最近看 wpa_supplicant 的代码,发现有许多的结构体都相互嵌套

什么情况下我们会选择这种相互嵌套的结构?

例如下面的 wpa_supplicant 和 wpa_global

exp:

struct wpa_supplicant {
    struct wpa_global *global;
    struct wpa_radio *radio; /* shared radio context */
    struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */
    struct wpa_supplicant *parent;
    struct wpa_supplicant *p2pdev;
    struct wpa_supplicant *next;
    struct l2_packet_data *l2;
    struct l2_packet_data *l2_br;
    unsigned char own_addr[ETH_ALEN];
    unsigned char perm_addr[ETH_ALEN];
    char ifname[100];
...
struct wpa_global {
    struct wpa_supplicant *ifaces;
    struct wpa_params params;
    struct ctrl_iface_global_priv *ctrl_iface;
    struct wpas_dbus_priv *dbus;
    struct wpas_binder_priv *binder;
    void **drv_priv;
    size_t drv_count;
    struct os_time suspend_time;
    struct p2p_data *p2p;
    struct wpa_supplicant *p2p_init_wpa_s;
    struct wpa_supplicant *p2p_group_formation;
    struct wpa_supplicant *p2p_invite_group;
...
4310 次点击
所在节点    C
14 条回复
wizardoz
2019-01-10 13:36:14 +08:00
这个不叫嵌套好吧,顶多算是一种关联。
wizardoz
2019-01-10 13:37:42 +08:00
就好比双向链表,a 的 next 指向 b,b 的 prev 指向 a。你不能说它是相互嵌套啊
jagger2048
2019-01-10 13:50:01 +08:00
相互嵌套 谈不上,用个结构体封装其他结构体指针,可以比较方便地管理资源,如果是 C++可以用类的某些特性(派生继承多态)来封装
aijam
2019-01-10 14:13:03 +08:00
爹认识儿子,儿子也要认识爹。
zn
2019-01-10 14:19:04 +08:00
这个叫互相引用,不叫互相嵌套。
GeruzoniAnsasu
2019-01-10 14:21:15 +08:00
这是个每个节点都带有指向根节点指针的树结构
wutiantong
2019-01-10 14:56:55 +08:00
99%的 C 语言项目都能看到这种“相互嵌套”,题主一定是没用 C 语言做过工程实践。
dazhangpan
2019-01-10 16:18:11 +08:00
有点就是互相都知道地址,去谁家串个门都方便
liuxey
2019-01-10 16:22:49 +08:00
互相引用这种事情别说 C,Java 里也很常见嘛,还记得一对多和多对多吗
reus
2019-01-10 16:25:03 +08:00
那是指针,存的是指针,没有嵌套

真的嵌套的话,是编译不过的,因为结构体大小是无限大,没法编译
flyingghost
2019-01-10 17:26:25 +08:00
相互嵌套。。。吓我一大跳,申请一个实例直接就爆内存了啊喂!

只是互相关联,互相存一个指针而已。莫慌,莫慌。
FrankHB
2019-01-10 20:33:11 +08:00
看起来是作者水平比较屎,因为无知或盲信 Linux Kernel Coding Style 5)之类的反智胡扯,不知道用显式类型体现更明确的目的(考虑到下面的 magic,前者跑不掉)。换 C 艹可能就被打死了。
真正互相引用的像链表的 prev/next 的情况理应是非常少的,并且基本可以且往往应该排除出业务代码。
然后看了下代码(主要是 wpa_supplicant_deinit_iface ),果然是属于混用所有权和链表访问的需要被打死的情况。在我这边 review 避免被打死的标准套路起手( C 艹版本)是 wpa_supplicant *ifaces 改成 pmr::list<wpa_supplicant> ifaces,struct wpa_global *global 改成 observer_ptr<wpa_global>。C 嘛要考虑的细节麻烦多了(……比如避免_t 踩到 POSIX reserve name ),懒得示范了。
FrankHB
2019-01-10 20:41:29 +08:00
贴漏了,observer_ptr<wpa_global>后补 global。另外看起来是内部用的,不管 ABI compat 直接改 pmr::forward_list 好了,更接近原逻辑。

@jagger2048 知道是 C 代码就别拿 C 艹的习惯说大话了,看看实际代码就知道不符合你这里说的任何一种情况(尽管看的确实是“资源管理”有点关系的代码)。
cwx391497
2019-01-11 08:13:12 +08:00
@GeruzoniAnsasu 谢谢,我数据结构就了解到链表那里,会去补一下相关知识

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/525672

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX