使用指向结构内部声明的字段的指针(也称为 CONTAINING_RECORD 宏)来计算指向整个结构的指针的可移植方法

2023-11-21

例如,在 Winnt.h 中定义了众所周知的 CONTAINING_RECORD() 宏:

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                              (PCHAR)(address) - \
                                              (ULONG_PTR)(&((type *)0)->field)))

或者在 FreeBSD 中:

#define CONTAINING_RECORD(addr, type, field)    \
      ((type *)((vm_offset_t)(addr) - (vm_offset_t)(&((type *)0)->field)))

或者在 Linux 中:

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

当然,在世界上许多其他地方也是如此。

但是,我怀疑它们是否符合标准。

增强源(boost _1_48_0/boost/intrusive/detail/parent_from_meber.hpp)而不是 让我失望 - 他们有 3 个 #ifdef PARTICULAR_COMPILER 案例:

template<class Parent, class Member>
inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member)
{
   //The implementation of a pointer to member is compiler dependent.
   #if defined(BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER)
   //msvc compliant compilers use their the first 32 bits as offset (even in 64 bit mode)
   return *(const boost::int32_t*)(void*)&ptr_to_member;
   //This works with gcc, msvc, ac++, ibmcpp
   #elif defined(__GNUC__)   || defined(__HP_aCC) || defined(BOOST_INTEL) || \
         defined(__IBMCPP__) || defined(__DECCXX)
   const Parent * const parent = 0;
   const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member));
   return std::ptrdiff_t(member - reinterpret_cast<const char*>(parent));
   #else
   //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC
   return (*(const std::ptrdiff_t*)(void*)&ptr_to_member) - 1;
   #endif
}

第二种情况(#if Defined GNUC and other))似乎是最常见的,但我不确定带有“零初始化”父级的指针算术是否定义良好(?)

所以我的问题是:

  1. CONTAINING_RECORD 又名container_of 宏实现中至少之一是否符合标准?

  2. 如果没有,是否存在一种符合标准的方法来使用指向结构内部声明的字段的指针来计算指向整个结构的指针?

  3. 如果没有,是否存在一种实用的便携式方法来做到这一点?

如果 C 和 C++ 的答案不同,我对这两种情况都感兴趣。


  1. 不,您提供的都不符合要求。取消引用空指针不是,typeof不是并且({ ... })表达式不是。

  2. 是的,linux 的第二部分已正确重写(type *)((char *)(ptr) - offsetof(type, member))是合规的。 (offsetof标准中定义)

  3. see 2

AFAIK,所有这些对于 C 和 C++ 都有效

Edit:linux 试图通过检查指向成员的指针和参数中的指针是否兼容赋值来为宏添加额外的安全性。据我所知 gcc 扩展typeof对于 C 中的这种方法至关重要。

对于 C99,您可以使用“复合文字”通过执行类似的操作来进行稍弱的检查

(type){ .member = *(ptr) }

但这只会告诉你如果类型*ptr赋值是否兼容member。例如如果ptr将会float*和会员double这仍然有效。

无论如何,类型检查只会给您带来虚假的安全性。你一定非常确定你的ptr真正来自内心type使用这个。当心。

Edit:正如 bert-jan 在下面的评论中所说,在 C++ 中,当存在虚拟继承时,offsetof宏的根本问题是无法在编译时确定成员的偏移量。我不相信当前容器宏的想法在这种情况下有任何意义。是极其小心。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用指向结构内部声明的字段的指针(也称为 CONTAINING_RECORD 宏)来计算指向整个结构的指针的可移植方法 的相关文章

随机推荐

  • r 中的 Shell 命令不适用于目录名称中的空格

    我正在尝试使用 shell 命令从 R 运行简单的外部应用程序 shell C Program Files SomeApp bin Release SomeApp exe C Users SomeUser R Scripts RProjec
  • 防御性编程[关闭]

    Closed 这个问题是基于意见的 目前不接受答案 在编写代码时 您是否有意识地进行防御性编程 以确保较高的程序质量并避免您的代码被恶意利用的可能性 例如通过缓冲区溢出漏洞或代码注入 您始终应用于代码的 最低 质量水平是什么 在我的工作中
  • 以编程方式捕获 LogCat 或将其导出到文件?

    我想过滤一个logcat String myCommand logcat f sdcard output txt no filters keep writing myCommand logcat d f sdcard output txt
  • iOS 6 中的 viewDidLoad 调用过一次吗?

    小心 这个问题与最近的弃用viewDidUnload 我见过 很棒 且合乎逻辑的答案围绕这个主题 但显然事实证明他们错了 请谨慎行事 正如您所看到的 这个主题非常令人困惑 来自苹果的文档 然而系统会自动释放这些昂贵的资源 当视图未附加到窗口
  • 输入尺寸与宽度

  • 定义条件路由

    我一直在寻找类似的东西 但没有运气 我想构建一个对相同网址使用不同控制器的应用程序 基本思想是 如果用户以管理员身份登录 他使用管理员控制器 如果用户只是用户 他使用用户控制器 这只是一个例子 基本上我想要一个函数来决定控制器路由采用什么
  • 是否有用于字符串自然排序的内置函数?

    我有一个字符串列表 我想对其执行自然字母排序 例如 以下列表是自然排序的 我想要的 elm0 elm1 Elm2 elm9 elm10 Elm11 Elm12 elm13 这是上面列表的 排序 版本 我使用的sorted Elm11 Elm
  • 我在 jQuery 中看到过这个 它有什么作用
  • iPhone X 上的 TableView 和 home 指示器

    我正在使用两者UITableViewController and UITableView在一个项目中 An UITableView in an UITableViewController覆盖 iPhone X 上的主页指示器 但是一个UIT
  • VIM:在 python 模式下使用 python3 解释器

    我最近切换到 vim 并将其配置为使用 Python 编程this教程 之前 我已经确保 vim 支持 python3 vim version 显示 python dyn 和 python3 dyn 使用this文章 但是当执行文件时pyt
  • 如何通过指定alpha混合量来计算RGB颜色?

    我正在编写一个颜色选择器 它可以从您指向屏幕上的任何位置获取像素 RGB 值 我还希望可以选择指定我选择的颜色已经具有 alpha 值 我只是想知道如何计算结果颜色 例如 生成的像素颜色为 240 247 249 但我知道原始颜色具有 10
  • 滚动角载荷数据 [For 循环]

    我正在显示与搜索词相关的数据 该数据一次性显示所有结果 我想要做的是一次显示 6 个数据 然后将剩余的数据加载到滚动条上 li category name li 如何滚动显示数据 你可以听window scroll当滚动到达页面底部时发生事
  • 从 Jenkinsfile 中的函数调用阶段

    我的 Jenkinsfile 中有 def foo 1 2 3 def parallelStagesFromMap foo collectEntries Build it generateStage it def generateStage
  • 如何正确模拟类的私有成员

    我正在尝试为依赖于另一个私有方法的方法编写一些单元测试 如下例所示 def is member of self group name members self get group members group name 我想模拟的私有方法是
  • 使用自定义证书文件在代理后面进行 Pip

    pip 的代理设置可以通过 proxy命令行选项或全局配置文件中 即 HOME config pip pip conf在Unix中 HOME Library Application Support pip pip conf在 OS X 中
  • 背景颜色十六进制到 JavaScript 变量

    我对 JavaScript 和 jQuery 有点陌生 现在我面临一个问题 我需要将一些数据发布到 PHP 其中一位数据需要是 div X 的背景颜色十六进制 jQuery 具有 css background color 函数 使用它我可以
  • 嵌套 ng-bootstrap 选项卡 (Angular 2)

    我正在尝试嵌套 ng bootstrap 选项卡小部件 但嵌套选项卡的内容未正确显示 当我单击嵌套选项卡时 内容本身就会消失 最小演示 我究竟做错了什么 这是查看代码
  • 在 WPF 中实现多停靠窗口系统(如 Blend、Visual Studio)

    您将如何实现如 Expression Blend 中所示的停靠工具箱窗口系统 您可以通过多种方式相互停靠工具箱窗口 如选项卡或浮动顶级窗口一样重叠 我的系统的行为应该与 Expression Blend 中的行为几乎相同 另外 我在拖动时获
  • cv2.drawContours不会绘制填充轮廓

    我正在尝试使用显示填充轮廓cv2 drawContoursOpenCV 中的函数 我已经从边缘图像中开发了一个轮廓列表 该边缘图像源自Canny检测 并找到轮廓RETR EXTERNAL为层次结构定义启用 然而我遇到了一个问题 尽管使用 1
  • 使用指向结构内部声明的字段的指针(也称为 CONTAINING_RECORD 宏)来计算指向整个结构的指针的可移植方法

    例如 在 Winnt h 中定义了众所周知的 CONTAINING RECORD 宏 define CONTAINING RECORD address type field type PCHAR address ULONG PTR type