c - 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;
}
解决方案
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 ,无论如何):bsearch
char *
char *
int *mem = (int *) malloc( N * sizeof *mem );
到处使用显式强制转换有点痛苦。
1989/1990 标准 (C89/C90) 引入了void
数据类型——它是一种不能存储任何值的数据类型。类型表达式void
仅针对其副作用(如果有)2进行评估。为该类型创建了一个特殊规则,以便该void *
类型的值可以分配给/从任何其他指针类型而不需要显式转换,这使其成为新的“通用”指针类型。 malloc/calloc/realloc
全部更改为 return void *
,回调现在接受参数而不是qsort
,现在事情变得更清晰了:bsearch
void *
char *
int *mem = malloc( sizeof *mem * N );
您不能取消引用 a void *
- 在我们上面的示例中,如果q
有 type void *
,我们无法在p
没有强制转换的情况下获得值:
printf( "p = %d\n", *(int *)q );
请注意,C++ 在这方面有所不同——C++ 没有void *
特殊处理,并且需要显式强制转换以分配给不同的指针类型。这是因为 C++ 提供了 C 没有的重载机制。
- 每个对象类型都应该可以映射到一个
char
. - 在 K&R C 中,所有函数都必须返回一个值 - 如果您没有显式键入函数,编译器会假定它返回
int
. 这使得很难确定哪些函数实际上是要返回一个值,哪些函数只有副作用。该void
类型对于键入不打算返回值的函数很方便。
推荐阅读
- r - 用条件对大数据框进行子集化
- java - 除括号外的管道之间拆分的正则表达式
- coq - Coq 在 Ensemble 上扩展判断平等
- python - 如何在 Jupyter 笔记本中设置 pandas.DataFrame.loc 输出的精度?
- swift - 如何从 SCNText iOS 获取浮点值?
- android - 无论用于启动它的方法如何,Android 活动都不会启动
- azure-devops - Azure Devops - 一段时间后删除的组织
- spring-boot - 如何使用 STS 本地启动服务
- linux - 我们如何显示手册页中提到特定人员的每个命令的名称
- java - 如何在帮助 selenium 的 html 中定位 ::before::after