• Linus Torvalds: You Don't understand pointer.


    Linus Torvalds在一次采访中(一次演讲后的Q&A)中被要求讲一下他最喜欢的Hack,讲着讲着,Linus就说,很多人都不懂如何使用指针,比如xxxxxxx.......

    原文如下:

    favorite hack
    by vlm

    I asked a bunch of hard architecture questions, now for a softball Q. Your favorite hack WRT kernel internals and kernel programming in general. drivers, innards, I don't care which. The kind of thing where you took a look at the code and go 'holy cow that's cool' or whatever. You define favorite, hack, and kernel. Just wanting to kick back and hear a story about cool code.

    Linus: Hmm. You do realize that I don't get all that close to the code any more? I spend my time not coding, but reading emails, and merging stuff others wrote. And when I *do* get involved with the code, it's not because it's "cool", it's because it broke, and you'll find me cursing the people who wrote it, and questioning their parentage and that of their pets.

    So I very seldom get involved in the really cool code any more, I'm afraid. I end up being involved in the "Holy sh*t, how did we ever merge that cr*p" code. Perhaps not as much as Greg (who has to deal with the staging tree), but then Greg is "special".

    That said, we do have lots of pretty cool code in the kernel. I'm particularly proud of our filename lookup cache, but hey, I'm biased. That code is *not* for the weak of heart, though, because the whole lockless lookup (with fallbacks to more traditional locked code) is hairy and subtle, and mortals are not supposed to really look at it. It's been tweaked to some pretty extreme degrees, because it ends up being involved any time you look up a filename. I still remember how happy I was to merge the new lockless RCU filename lookup code last year.

    At the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc. For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like

    if (prev)
    prev->next = entry->next;
    else
    list_head = entry->next;

    and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.

    People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a "*pp = entry->next".

    So there's lots of pride in doing the small details right. It may not be big and important code, but I do like seeing code where people really thought about the details, and clearly also were thinking about the compiler being able to generate efficient code (rather than hoping that the compiler is so smart that it can make efficient code *despite* the state of the original source code).

    这是一个关于如何在一个单链表中删除一个节点的问题。显然Linus所提到的“很多人的做法”,确实比较像newbies写出来的东西。

    其实,一般教科书上都会采用这样一种写法(链接):

    也就是在链表的头部放一个没用的“头”(Dummy Node)。不赘述。

    还有一种方法就是Linus所说的,用一个指向指针的指针,这样写的代码就能够简洁。平心而论,这个是比较难懂,但是当你懂得之后,会发现确实是一个非常简洁的方法。

    一个非常有助于理解的链接是这里

    Linus所反对的做法是:

    if (prev)
      prev->next = entry->next;
    else
      list_head = entry->next;

    这里,要检查一下所指的是不是链表头,如果是链表头的话,采取的措施不一样。的确有点累赘。

    (这里要注意的是我们没有写free掉那个node的代码,毕竟不一定需要free,而且,free的方法也多种多样。)

    把上面的代码写成完整的一个函数:

    void remove_elem(int value, linkedlist **p_list_head) { // removes an element from a list by its value
        linkedlist *entry = *p_list_head;                   // starting at the head of the list...
        linkedlist *prev = NULL;                            // which has no previous element...
        while (entry) {                                     // while we have a non-null entry (not the end of the list)...
            if (entry->value == value) {                    // if this node needs to be removed...
                if (prev)                                   // if there was a previous node (this is not the head)...
                    prev->next = entry->next;               // have the previous node point to the node after this...
                else                                        // otherwise if this node is the head...
                    *p_list_head = entry->next;             // replace the head of the list with the following node...
            } else {                                        // otherwise if this entry does not need to be removed...
                prev = entry;                               // mark this entry as 'previous'...
            }
            entry = entry->next; // and move to the next entry
        }
    }
    //这里省略了free的代码,仅仅是将那个对应的entry扔掉而已

    Linus认为,好一点的代码应该是这样:

    void remove_elem(int value, linkedlist **p_list_head) { // removes an element by its value
        linkedlist **pp = p_list_head;                      // starting at the head of the list...
        while (*pp) {                                       // while we have a non-null entry (not the end of the list)...
            if ((*pp)->value == value)                      // if this node needs to be removed...
                *pp = (*pp)->next;                          // have the list skip this entry...
            else                                            // otherwise if this entry does not need to be removed...
                pp = &((*pp)->next);                        // move to the next entry
        }
    }
    //注意这里省略了free掉那个node的代码

    更多的解释在这里

    其实,要理解上面那个好一点的 remove_elem 什么意思,主要要理解那个“指向指针的指针”是怎么操作的:

    ---------     ---------     ---------
    | a | --+---> | b | --+---> | c | 0 |
    ---------  ^  ---------     ---------

                            |

                 操控这个指针

    使之指向下一个:

    ---------     ---------     ---------
    | a | --+--+  | b | --+---> | c | 0 |
    ---------  |  ---------     ---------
               |                ^
               +----------------+

    这样就不用管当前的entry是head还是其他了。nice。

    :)

  • 相关阅读:
    从IL角度彻底理解回调_委托_指针
    微信个人机器人开发
    个人微信接口开发
    淘客微信接口
    python爬虫添加请求头代码实例
    用 Django 开发一个 Python Web API
    Common encryption methods and implementation in Python Python中常用的加密方法及实现
    python aes加密
    # Python语言程序设计基础
    Python语言程序设计基础——4 程序的控制结构
  • 原文地址:https://www.cnblogs.com/walkerlala/p/5467213.html
Copyright © 2020-2023  润新知