在池的实现中从 void* 转换为 char*

Conversion from void* to char* in an implementation of pool

在一个基本池的实现中,我有这样的东西(我将简化代码以使其更清晰)

struct unit_header{
  struct unit_header* next, prev;
};
int number_of_units = 10
int unit_size = 5;
int full_block = number_of_units*(unit_size+sizeof(struct unit_header));

void* p_mem_full_block = malloc(full_block);

//iterate all units of mem_full_block
for (int i = 0; i< number_of_units; i++){
  //pointer to each unit
  struct unit_header* p_units = (struct unit_header*)((char*)p_mem_full_block + i*(unit_size+sizeof(struct unit_header)));
  //.... some pointers stuff....
}

我知道这部分(下面)用于遍历 mem_block 的所有单元...

i * (unit_size+sizeof(struct unit_header))

我没明白这部分是什么:

(char*)p_mem_full_block

意思是。为什么我必须进行此 char* 转换?

这是因为根据C标准你不能对void *进行任何加减运算;然而,加法和减法是为 char * 定义的,它们将指针前进给定的 字节数 .

但是,GCC 允许 void pointer 算法作为扩展而不会发出警告,除非由 -Wpointer-arith-Wpedantic 等启用。


此外,整个操作看起来不太可移植,因为 unit_header 结构的对齐要求可能与 unit_size 的倍数不同。实际上,5 的 unit_size 会导致问题,并且在许多处理器上,此类代码会编译但在运行时崩溃,因为指针(prevnext)未对齐,例如实现可能需要一个可被 4 或 8 整除的地址,而代码将允许介于两者之间的任何数字。然而,x86 本身通常不太关心错误对齐。

两种指针类型之间的转换产生的结果未正确对齐根据 C11 具有未定义的行为。