Linus Torvalds 在 TED 演讲上所说的有品味的代码

2022 年 5 月 19 日
 Biwood

需求是从单向链表中删除一个指定节点。

教科书上的(普通的)写法:

void remove_cs101(list *l, list_item *target)
{
        list_item *cur = l->head, *prev = NULL;
        while (cur != target) {
                prev = cur;
                cur = cur->next;
        }
        if (prev)
                prev->next = cur->next;
        else
                l->head = cur->next;
}

优雅的(有品味的)写法:

void remove_elegant(list *l, list_item *target)
{
        list_item **p = &l->head;
        while (*p != target)
                p = &(*p)->next;
        *p = target->next;
}

目测充分利用的指针的特性,代码量少了不少。

代码仓库和详细解释在这里: https://github.com/mkirchner/linked-list-good-taste/blob/main/README.md

13768 次点击
所在节点    程序员
120 条回复
luxor
2022 年 5 月 20 日
@Biwood 原文最大的问题就是只从源码角度来评判。是不是高效的代码,编译后才能见真章。通常而言,更好的算法也是更高效的,但原文的例子是个例外。我认为主要原因还是例子的逻辑太简单,源码写得再烂,编译器都给优化掉了。因此还是不要过分的炫技,免得打脸。https://godbolt.org/z/6qo3Yqez3
bthulu
2022 年 5 月 20 日
@masterclock 写内核的都是工作之余用爱发电, 在能用的情况下, 当然是怎么快怎么来了
cnbatch
2022 年 5 月 20 日
既然有人提到了 container_of ,刚好几个星期前在另一个帖子就聊过,我觉得可以再把例子拿出来说一次。

先来看看 Linux 最经典的用了 GCC 内置扩展的写法:

#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })

来源: https://github.com/torvalds/linux/blob/master/tools/include/linux/kernel.h


然后是最新的 container_of ,经过多年进化,新版本已经不需要用 GCC 内置扩展:

#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })

来源: https://github.com/torvalds/linux/blob/master/include/linux/container_of.h


相信不少人已经相当熟悉了,它的具体原理没必要再解释。



换换口味,再来看看 FreeBSD 的写法:

#define container_of(p, stype, field) ((stype *)(((uint8_t *)(p)) - offsetof(stype, field)))

来源: https://github.com/freebsd/freebsd-src/blob/main/sys/dev/cxgb/cxgb_adapter.h

一目了然,简洁易懂。


所以说,想要同时兼顾“更易理解”、“更少行数”,总会有办法的,尽管可能需要等很多年。

主题所讲的从教科书到 Linux 手动优化,显然也是教科书的做法出现得最早。所以或许以后会有人想得出更易理解但行数也不多的写法吧。
lslqtz
2022 年 5 月 20 日
不一定所有场合都需要如此优雅是真的,我只能说。。
iamzuoxinyu
2022 年 5 月 20 日
> #define container_of(p, stype, field) ((stype *)(((uint8_t *)(p)) - offsetof(stype, field)))

这个没法保证类型安全吧。
icyalala
2022 年 5 月 20 日
@luxor 看了下汇编,确实第一种反而好些。

我觉得 Linux 强调的是 "a special case goes away and becomes the normal case",那段代码只是个做个例子:"But this is simple code. This is CS 101. This is not important."

如果说性能的话,我记得很深: <amp-youtube data-videoid="LUVFgeQKgK8" layout="responsive" width="480" height="270"></amp-youtube> 去年有人翻出来 Linus 第一次参加大型会议的演讲,那时他才 24 岁。他说他自己是 "performance freak",喜欢每隔一段时间就看看 kernel 编译后的汇编结果,然后返回来改 C 原码来得到更好性能,因此实际会出现些不好的代码,因为那是为 gcc 特别改的。
Kylin30
2022 年 5 月 20 日
优雅快捷键:alt+enter
cnbatch
2022 年 5 月 20 日
@cnbatch #63 我还是一时大意了,实际上新版 container_of 写法仍然还是用了 GCC 内置扩展 __same_type

@iamzuoxinyu 需要强制检查的时候,FreeBSD 部分地方仍然提供了依赖扩展功能 typeof 的的版本

https://github.com/freebsd/freebsd-src/blob/main/sys/dev/drm2/drm_os_freebsd.h

#define container_of(ptr, type, member) ({ \
__typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

两者的差异就在于是否想彻底实施 C 语言的“哲学”:相信程序员
smdbh
2022 年 5 月 20 日
当初看很兴奋,为了通用化,减少分支。喜欢 if else 的看到嵌套十几层的不会有反感的
greygoo
2022 年 5 月 20 日
你是对的,也看了下 clang 的结果但是两种循环里面的指令都多了一条 lea
sparky
2022 年 5 月 20 日
有意思,c 语言吃透指针果然各种玩法
ericguo
2022 年 5 月 21 日
那么明显的第二种好,当然我承认我第一次写多半也是第一种。
lesismal
2022 年 5 月 21 日
二级指针看着挺舒服的
zhzhh
2022 年 5 月 21 日
看了好一会儿才想清楚(我好菜啊哈哈
pmispig
2022 年 5 月 21 日
代码量少有什么好处?优雅的代码有 2 个要素: 1:性能 2:易懂。
代码量从来不是是否优雅的标准。
holydancer
2022 年 5 月 21 日
看了两遍才看懂 2 的实现,太久没接触 C 了
完全理解后觉得,指针熟练的人,可能确实写 2 出错概率更低,且效率更高,完全是下意识。
高级语言用多的人,会下意识排斥 2 的写法。
junyee
2022 年 5 月 21 日
* 老大开口,言听必从。

* 凡文言文必给 0 分。

C 语言渣渣路过。。。
ZhiyuanLin
2022 年 5 月 22 日
觉得 2 可读性不如 1 ,可能是太久没写 C 了……
指针也不是啥高级特性
jedihy
2022 年 5 月 22 日
2 在 kernel 里面是常规操作了,我自己也是这么写很多年了。
WispZhan
2022 年 5 月 22 日
2 确实是目前最优雅的解

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

https://study.congcong.us/t/854016

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

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

© 2021 V2EX