假设我有struct
喜欢:
typedef struct S S;
struct S {
S *next;
// ...
S *gc_next;
};
即,它包含多个" next"指针同时在多个链表上。如果我想编写一个可以跟随任何" 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;
}
}
其中PTR_OFFSET
是一个宏,给定指向某个struct
的指针,我想要的成员类型(在本例中为S*
),以及成员的偏移量我想,然后取消引用该指针,我可以获得所需成员的值。
要获得偏移量,我可以编写一个前端宏来调用使用S_free_impl()
的{{1}}:
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
抑制警告的一种方法是编写一种C语言的C ++等同于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 );
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:
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) )
投射警告而消失。
问题是:这是在C中获得我想要的最好(最便携)方式吗?具体做法是:
uintptr_t
成员(相同类型)进行操作的函数。struct
返回的值的可移植方式,将其转换为指向成员的实际指针。