【问题标题】:How to retrieve the structure holding a pointer with container_of macro如何使用 container_of 宏检索包含指针的结构
【发布时间】:2018-03-05 19:01:02
【问题描述】:

我使用的宏con​​tainer_of定义为:

#define container_of(ptr, type, member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)))

结构向量:

struct vector {
    uint32_t signature;
    size_t element_size;
    size_t size;
    void *data;
};

最后是函数vectorSize 接收指向一些数据的指针。此函数不起作用,因为只有 struct vector v 中的 data 成员具有正确的值,其他成员有垃圾,导致 if 语句 SIGNATURE 失败。

size_t vectorSize(void *vec)
{
    void **pdata = &vec;
    struct vector *v = container_of(pdata, struct vector, data);

    if (v->signature != VECTOR_SIGNATURE) return 0;
    return v->size;
}

我的设置有什么问题?

【问题讨论】:

  • 我不明白。如果指针的容器没有正确初始化,为什么要怪宏呢?
  • @EugeneSh。容器已正确初始化。但是当我用 container_of 检索它时,只有数据指针设置正确
  • 因为vec 参数不是vector 结构的成员。它可能是这样一个成员的副本,但这无济于事。
  • @interjay 好点。很难发现...pdata 必须是成员的实际地址。目前它是 vec 参数的地址。您可能希望更改函数的签名以获取实际地址。
  • 我不明白你的宏,你为什么要做1 ? (ptr) : ... 在条件为真时使用?: 运算符有什么意义?

标签: c pointers void-pointers


【解决方案1】:

首先,请不要发布1 ? this : that之类的代码。我知道,这是您在深入研究问题时提供的实验代码。但它不应该在这里发布,因为它会让我们感到困惑。

如果我没听错的话,你的函数接收到一个指向结构成员的指针,你需要一个宏来传递容器结构。试试这个:

#define CONTAINER_OF(MemberPtr, StrucType, MemberName) ((StrucType*)( (char*)(MemberPtr) - offsetof(StrucType, MemberName)))

接着是:

size_t vectorSize(void *vec)
{
    struct vector *v = CONTAINER_OF(vec, struct vector, data);

    if (v->signature != VECTOR_SIGNATURE) return 0;
    return v->size;
}

【讨论】:

    【解决方案2】:

    container_of 宏的示例用法:

    struct vector *vector_of(void* element) 
    {
        return container_of(element, struct vector, data);
    }
    

    对于您的实现,在我看来它应该是这样的:

    size_t vector_size(void *vec_ptr)
    {
        struct vector *vec = v_ptr;
        return vec->signature != VECTOR_SIGNATURE ? 0 : vec->size;
    }
    

    【讨论】:

      【解决方案3】:

      由于数据是 (void *) 类型,vec 必须是 (void **)。 但是你不应该给出 vec 的地址。 相反,只需将其转换为 (void **)。如下:

      struct vector *v = container_of((void **)vec, struct vector, data);
      

      【讨论】:

      • 我假设container_of宏与linux内核中定义的宏相同。在这种情况下,您必须强制转换它以避免编译错误。你应该只传递vec 本身的值来获取container 的正确地址。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-25
      • 1970-01-01
      • 1970-01-01
      • 2018-05-30
      相关资源
      最近更新 更多