RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 904251
Accepted
Ain Mditrevi
Ain Mditrevi
Asked:2020-11-09 15:03:38 +0000 UTC2020-11-09 15:03:38 +0000 UTC 2020-11-09 15:03:38 +0000 UTC

C中的这个表达式是什么?

  • 772

在代码中找到这一行:

void *ptr = ((char*)l_p - (unsigned int)&((struct node_s*)0)->list);

我不明白它在这种情况下的含义&以及为什么在这种情况下使用它unsigned int。如果可能,请用文字解释。

结构本身的表示在这里:

struct node_s{
    char a;
    char b;
    char c;
    char d;
    struct list_head list;
};
linux
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    AnT stands with Russia
    2020-11-09T15:16:04Z2020-11-09T15:16:04Z

    这是一个经典的 hack,用于实现所谓的功能container_of,它允许您从指向已知结构类型字段的指针获取指向此结构类型的整个对象的指针。

    子表达式

    (unsigned int)&((struct node_s*)0)->list
    

    这本身就是一个单独的 hack,用于实现类似于标准宏的功能offsetof。list此子表达式计算结构类型中字段的字节偏移量struct node_s。在给定的平台上,显然子表达式

    (struct node_s*)0
    

    将生成指向0x0类型地址的指针(struct node_s *),即 指向struct node_s位于 address的某个类型的虚构对象的指针0x0。因此,子表达式

    ((struct node_s*)0)->list
    

    将是list这个假想物体的场。由于我们的虚构对象从 开始0x0,因此该字段的地址

    &((struct node_s*)0)->list;
    

    将在数值上等于list该虚构对象中字段的字节偏移量,即 在类型中struct node_s。只需将此指针转换为整数类型

    (unsigned int)&((struct node_s*)0)->list
    

    我们以字节为单位获取偏移量本身(假设它适合unsigned int;在这里强制转换为类型会更合适uintptr_t)。

    由于在这些操作过程中,我们从不尝试写入或读取这个虚构对象的内容,而只是使用它来计算地址,因此不会发生崩溃。

    现在,如果l_p是指向list某个真实对象字段的指针struct node_s,那么算术

    ((char*)l_p - (unsigned int)&((struct node_s*)0)->list)
    

    会给我们一个指向对象本身的指针struct node_s(尽管是 type char *)。这就是一切。

    再一次,您的原始表达式可以通过标准宏更紧凑地重写offsetof

    void *ptr = (char*)l_p - offsetof(struct node_s, list);
    

    并且会有更少的黑客攻击。而且,如上所述,此功能通常称为container_of. 你原来的表达方式几乎一模一样

    void *ptr = container_of(l_p, struct node_s, list);
    

    在这个表达式中完成的大多数操作(尤其是模拟部分offsetof)在 C 语言中是严重非法的,因为它们会产生未定义的行为。也就是说,如上所述,这是一个 hack。

    另一个问题是这段代码是“手工”编写的,还是标准宏扩展的结果(相同offsetof)。对于标准宏,允许使用这种技巧(尽管标准库的现代实现已经放弃了它们的使用)。对于用户代码,如果没有明确的需求,这样的技巧是很难接受的(但有时你不能没有它们)。

    • 19

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5