链表功能说明,结构指针的预订

时间:2018-09-27 15:33:30

标签: c linked-list singly-linked-list

用C编写一个简单的单链列表,我在Github上找到了这个存储库:https://github.com/clehner/ll.c,同时在寻找一些示例。
有以下功能(_list_next(void *)):

struct list 
{
    struct list *next;      // on 64-bit-systems, we have 8 bytes here, on 32-bit-systems 4 bytes.
    void *value[];          // ISO C99 flexible array member, incomplete type, sizeof may not be applied and evaluates to zero.
};

void *_list_next(void *list)
{
    return list ? ((struct list *)list)[-1].next : NULL;   // <-- what is happening here?
}

您能解释一下它是如何工作的吗?
似乎他在将空指针投射到列表指针,然后下标该指针。那是如何工作的以及在那里到底发生了什么?
我不了解[-1]的目的。

1 个答案:

答案 0 :(得分:1)

这是未定义的行为,恰好在作者尝试过的系统上起作用。

要了解发生了什么,请注意_ll_new的返回值:

void * _ll_new(void *next, size_t size)
{
    struct ll *ll = malloc(sizeof(struct ll) + size);
    if (!ll)
        return NULL;
    ll->next = next;
    return &ll->value;
}

作者为您提供value的地址,而不是节点的地址。但是,_list_next需要地址struct list:否则将无法访问next。因此,要成为next成员,您需要通过向后退一个成员来查找其地址。

这是在list处对[-1]进行索引的想法-它获得与此特定地址next关联的value的地址。但是,此操作会将数组索引超出其有效范围,这是未定义的行为。

其他函数也可以这样做,但是它们使用指针算术而不是索引。例如,_ll_pop使用

ll--;

达到相同的结果。

一种更好的方法是使用类似于container_of macro的东西。