0

假设我有一个struct喜欢:

typedef struct S S;
struct S {
    S *next;
    // ...
    S *gc_next;
};

即,它包含多个“下一个”指针同时位于多个链表上。如果我想编写一个可以跟随任何“下一个”指针的函数,我可以传递我想要的“下一个”指针的偏移量,例如:

void S_free_impl( S *p, size_t next_offset ) {
    while ( p ) {
        S *next = *PTR_OFFSET( p, S*, next_offset );
        free( p );
        p = next;
    }
}

wherePTR_OFFSET是一个宏,给定一个指向 some 的指针struct,我想要的成员的类型(在这种情况下,S*),以及我想要的成员的偏移量,然后取消引用该指针,我可以获得想要的成员的值。

要获得偏移量,我可以编写一个前端宏来调用S_free_impl()offsetof

#define S_FREE(PTR,NEXT)         S_free_impl( (PTR), offsetof( S, NEXT ) )

然后像这样使用它:

S_FREE( p, gc_next );            // free nodes following "gc_next" pointer

宏的初始实现PTR_OFFSET可以是:

#define PTR_OFFSET(PTR,TYPE,OFFSET) \
    (TYPE*)((char*)(PTR) + (OFFSET))

但是,如果你编译,比如说,使用gcc -Wcast-align,你会得到:

foo.c:21:24: warning: cast from 'char *' to 'S **' (aka 'struct S **') increases
      required alignment from 1 to 8 [-Wcast-align]
            S *next = *PTR_OFFSET( p, S*, next_offset );
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

抑制警告的一种方法是编写一种与 C++ 等效的 C reinterpret_cast

#define REINTERPRET_CAST(T,EXPR)  ((T)(uintptr_t)(EXPR))

然后重写PTR_OFFSET以使用它:

#define PTR_OFFSET(PTR,TYPE,OFFSET) \
    REINTERPRET_CAST( TYPE*, REINTERPRET_CAST( char*, (PTR) ) + (OFFSET) )

然后警告消失,因为通过a投射uintptr_t


问题是:这是在 C 中获得我想要的东西的最佳(最便携)方式吗?具体来说:

  1. struct编写对不同成员(相同类型)进行操作的函数的能力。
  2. 一种使用返回的值offsetof将其转换为实际指向成员的指针的可移植方式。
4

0 回答 0