c - 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?
}
你能解释一下这是如何工作的吗?
看起来他正在将一个 void 指针转换为一个列表指针,然后下标该指针。这是如何工作的,那里到底发生了什么?
我不明白[-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
这就是索引at背后的想法[-1]
- 它获取与 的next
特定地址相关联的地址value
。但是,这会将数组索引到其有效范围之外,这是未定义的行为。
其他函数也这样做,但它们使用指针算法而不是索引。例如,_ll_pop
使用
ll--;
达到相同的结果。
更好的方法是使用类似于container_of
macro的东西。
推荐阅读
- css - CSS Transitions and animations not working
- php - 在 Laravel 8 中使用 SendGrid 发送电子邮件
- python - 如何访问在类的方法中定义的变量?
- docker - 带有反应的docker nginx服务器的CORS错误 - axios
- html - 如何将要点设置在文本顶部?
- python - 编写已经运行的 event_loop 以添加新任务的简单方法
- ruby-on-rails - Rspec 测试不更新保存!从行动
- java - 如何引用接口以与实现它的类进行交互?
- javascript - 从输入更改锚点“onclick”属性的某些部分
- wordpress - Wordpress WPForm 数据库字段问题