一个实际工程中的 C 语言问题

2019-08-15 16:42:23 +08:00
 feng32

有一个 Linux 驱动模块,它会给每个设备分配一个数据结构

struct A {
    ...
    struct list_head list;
    ...
}

这个数据结构内含一个 “带头节点的双向循环链表”,这个 struct list_head 是 Linux 内核中的一个标准结构

struct list_head {
    struct list_head *prev;
    struct list_head *next;
}

一开始的时候,链表为空,只有一个头节点,所以 prev 指向自己,next 也指向自己

当系统上有两个设备的时候,就会产生 2 个结构体 a1 和 a2,同时也会产生两条链表

现在,出于一些原因,我需要让 a1 和 a2 共享一条链表。把 struct A 中的 struct list_head list 改为 struct list_head *list 这个方案看起来很直接,但是一旦这么改,代码中其它数百处引用这个 list 成员的地方,就需要一一修改了,成本很高。

如果能让 list 变成类似 C++ 中的引用变量,似乎可以解决问题,但是 Linux Kernel 不支持 C++

请问 C 语言里,是否还存在一些其它的可能性,可以避免更新所有引用 list 变量的代码?

2252 次点击
所在节点    程序员
16 条回复
wutiantong
2019-08-15 16:55:48 +08:00
先分析清楚你的业务场景吧,不要一上来就一通乱改。
feng32
2019-08-15 17:13:14 +08:00
@wutiantong 我已经故意把业务场景隐去了,这里讨论的就是 C 语言的奇技淫巧
takemeh
2019-08-15 17:14:00 +08:00
每个设备对应的结构体里面的链表头是放什么数据的呢?
另外膜拜写内核的大佬.
feng32
2019-08-15 17:16:57 +08:00
@takemeh 链表里装的数据是另一个 struct B,和这个问题没什么关系

内核里的 list_head 和学校里学的传统链表不太一样,可以参考这篇文章:

https://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html
msg7086
2019-08-15 17:21:06 +08:00
你改成引用变量也要改签名吧,一样的。
cqcsdzmt
2019-08-15 17:27:00 +08:00
a1->list->prev=b1->list->prev;
a1->list->next=b1->list->next;
....
cqcsdzmt
2019-08-15 17:29:33 +08:00
如上问题,骚 easy 的东西为什么想的这么复杂。
cqcsdzmt
2019-08-15 17:31:25 +08:00
更正一下
a1.list->prev=b1->list->prev;
a1.list->next=b1->list->next;
cqcsdzmt
2019-08-15 17:31:42 +08:00
更正一下
a1.list->prev=b1.list->prev;
a1.list->next=b1.list->next;
feng32
2019-08-15 17:58:46 +08:00
@cqcsdzmt 如果没有对 head 取地址的操作,那么它就是对的,但是实际上在 linux kernel 的使用场景下,它是有问题的

list_head 链表的遍历,就是不断 next 一直到达原先的 head,如果这么赋值,对 a1 的遍历就死循环了
feng32
2019-08-15 18:06:58 +08:00
@msg7086 如果大多数情况引用的是 struct A,函数签名里就没有 list 的类型了,所以这还是有很大作用的
reus
2019-08-15 18:10:58 +08:00
menyakun
2019-08-15 18:34:57 +08:00
好像没办法不改吧,我怎么感觉这个 list 结构应该放在设备的 inode 中,然后在 open 的时候,`file->private_data->list = list`这样
secondwtq
2019-08-15 18:56:43 +08:00
... 正解就是让电脑帮你去改

用奇技淫巧只会留下更多坑
boywhp
2019-08-15 20:50:44 +08:00
全局定义一个 struct list_head xxList = {0};
waruqi
2019-08-16 07:48:41 +08:00
A 里面还是改成 *list 不过所有操作 list 的 api 你用宏做下替换,比如之前是 insert(&list, x) ,用法保持不变 你写个 insert 宏替换之前的 insert func

#define insert_org insert
#define insert(list, x) insert_org(*(list), x)

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

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

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

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

© 2021 V2EX