首页 > 解决方案 > void * 指针是否用于 C 中的泛型类型?

问题描述

我经常看到 void 指针与其他类型的指针来回转换,我想知道为什么,我看到 malloc() 返回一个在使用之前也需要转换的 void 指针。

我对 C 语言非常陌生,并且来自 Python,所以指针是一个非常新的概念,可以让我一头雾水。

void * 指针的目的是提供一些“动态”类型吗?

以这段代码为例,它是有效的代码吗?

struct GenericStruct{
    void *ptr;
};

// use void pointer to store an arbitrary type?
void store(struct GenericStruct *strct, int *myarr){
    strct->ptr = (void *) myarr;
}

// use void pointer to load an arbitrary type as int*?
int *load(struct GenericStruct *strct){
    return (int *) strct->ptr;
}

标签: cpointersimplicit-conversionvoid

解决方案


a 的目的void *是为 C 的一些打字规则提供一个受欢迎的例外。除了 之外void *,您不能将一种类型的指针值分配给没有强制转换的不同指针类型的对象 - 例如,您不能编写

int p = 10;
double *q = &p; // BZZT - cannot assign an int * value to a double *

分配给不同类型的指针时,您必须显式转换为目标类型:

int p = 10;
double *q = (double *) &p; // convert the pointer to p to the right type before assigning to q

除了一个void *

int p = 10;
void *q = &p; // no cast required here.

在过去的 K&R C 中,char *被用作“通用”指针类型1 - 内存分配函数malloc/calloc/realloc全部返回char *,回调函数qsort和参数等,但是因为你不能直接分配不同的指针类型,你必须添加一个明确的演员表(如果目标不是 a ,无论如何):bsearchchar *char *

int *mem = (int *) malloc( N * sizeof *mem );

到处使用显式强制转换有点痛苦。

1989/1990 标准 (C89/C90) 引入了void数据类型——它是一种不能存储任何值的数据类型。类型表达式void仅针对其副作用(如果有)2进行评估。为该类型创建了一个特殊规则,以便该void *类型的值可以分配给/从任何其他指针类型而不需要显式转换,这使其成为新的“通用”指针类型。 malloc/calloc/realloc全部更改为 return void *,回调现在接受参数而不是qsort,现在事情变得更清晰了:bsearchvoid *char *

int *mem = malloc( sizeof *mem * N );

您不能取消引用 a void *- 在我们上面的示例中,如果q有 type void *,我们无法在p没有强制转换的情况下获得值:

printf( "p = %d\n", *(int *)q );

请注意,C++ 在这方面有所不同——C++ 没有void *特殊处理,并且需要显式强制转换以分配给不同的指针类型。这是因为 C++ 提供了 C 没有的重载机制。


  1. 每个对象类型都应该可以映射到一个char.
  2. 在 K&R C 中,所有函数都必须返回一个值 - 如果您没有显式键入函数,编译器会假定它返回int. 这使得很难确定哪些函数实际上要返回一个值,哪些函数只有副作用。该void类型对于键入不打算返回值的函数很方便。


推荐阅读