从 malloc 的自定义内存分配器中,考虑以下两个宏:
#define GET_HDR(bp) (*(int *)((int *)(bp) – 1))
#define GET_HDR(bp) (*(int *)((char **)(bp) – 1))
这里bp
是一个void
指针。
GET_HDR(bp)
用于获取 HEADER
的内容,该 是存储在 void 指针bp
之前的 4 字节块。在这里,第一个宏获取 void 指针 bp
,将其类型转换为 int 并减去 1 以返回指针 4 个字节,以便它指向HEADER
块,然后取消引用指针以给出HEADER
块的值。
但是第二个宏是如何做到的呢?如何操纵指针到达HEADER
块?
可能假定char *
的大小与int
相同。
(
*(int *)( /* Treat result as pointer to int and dereference */
(char **)(bp) /* bp is cast to a pointer to (char *) */
– 1 /* take bp back sizeof(char *) bytes (presumably also 4) */
)
)
就是指针,但指针算术取决于type
。如果 int
和 char *
的大小不同,则在减去 1 时,宏在内存中的偏移量不会相同。然后再次强制转换为*(int *)
以获取值时,最终可能会得到不同的结果。
使用指针算术时必须小心。如果系统上的int
和char *
不同,就会出现问题。例如,在x86_64
指针大小为8-bytes
,int
的大小为4-bytes
。在x86
指针大小为4-bytes
,int
的大小也4-bytes
。
当您投(int *)(bp) - 1
时,您要求在任何具有4-byte int
的系统上bp
之前(或bp
之前4-bytes
指针 - 涵盖大多数系统)。但是,在x86_64
上投(char **)(bp) - 1
会要求在bp
之前8-bytes
指针,而x86
上4-bytes
之前。这可能会导致问题。
在宏中强制转换为不同类型时还必须小心,并避免违反严格的别名规则。请参阅 C 标准的第 6.5.6
节和第 6.5.7
节。这里不涉及,但如果您依赖于宏中的多个强制转换,您可能会掩盖违规行为。