今天在阅读别人的代码时,我看到了类似的东西void *func(void* i);
,void*
这里的函数名和变量类型分别是什么意思?
另外,我们什么时候需要使用这种指针以及如何使用呢?
今天在阅读别人的代码时,我看到了类似的东西void *func(void* i);
,void*
这里的函数名和变量类型分别是什么意思?
另外,我们什么时候需要使用这种指针以及如何使用呢?
指向的指针void
是“通用”指针类型。Avoid *
可以在没有显式转换的情况下转换为任何其他指针类型。您不能取消引用 avoid *
或对其进行指针运算;您必须首先将其转换为指向完整数据类型的指针。
void *
通常用于需要能够在同一代码中使用不同指针类型的地方。一个经常被引用的例子是库函数qsort
:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
base
是数组的地址,是数组nmemb
中元素的数量,size
是每个元素的大小,compar
是指向比较数组中两个元素的函数的指针。它被这样调用:
int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);
数组表达式iArr
, dArr
, 和lArr
在函数调用中从数组类型隐式转换为指针类型,并且每个表达式都从“指向int
/ double
/ long
”的指针隐式转换为“指向void
”。
比较函数看起来像:
int compareInt(const void *lhs, const void *rhs)
{
const int *x = lhs; // convert void * to int * by assignment
const int *y = rhs;
if (*x > *y) return 1;
if (*x == *y) return 0;
return -1;
}
通过接受void *
,qsort
可以处理任何类型的数组。
使用的缺点void *
是您将类型安全扔出窗外并进入迎面而来的交通。没有什么可以保护您免于使用错误的比较例程:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareInt
期望它的参数指向int
s,但实际上是在使用double
s。没有办法在编译时发现这个问题;你只会得到一个错误的数组。
使用 void * 意味着该函数可以采用不需要是特定类型的指针。例如,在套接字函数中,您有
send(void * pData, int nLength)
这意味着您可以通过多种方式调用它,例如
char * data = "blah";
send(data, strlen(data));
POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));
C在这方面表现出色。可以说void
是虚无void*
就是一切(可以是一切)。
正是这个微小*
的差异。
雷内指出了这一点。Avoid *
是指向某个位置的指针。如何“解释”的内容留给用户。
这是在 C 中拥有不透明类型的唯一方法。非常突出的示例可以在例如 glib 或通用数据结构库中找到。在“C 接口和实现”中对其进行了非常详细的处理。
我建议您阅读完整的章节并尝试理解“get it”指针的概念。
void*
是一个“指向内存的指针,不假设存储的是什么类型”。例如,您可以使用,如果您想将参数传递给函数,并且该参数可以是多种类型,并且在函数中您将处理每种类型。
您可以查看这篇关于指针的文章http://www.cplusplus.com/doc/tutorial/pointers/并阅读章节:void pointers。
这也适用于 C 语言。
void 类型的指针是一种特殊类型的指针。在 C++ 中,void 表示没有类型,因此 void 指针是指向没有类型的值的指针(因此也是未确定的长度和未确定的取消引用属性)。
这允许 void 指针指向任何数据类型,从整数值或浮点数到字符串。但是作为交换,它们有一个很大的限制:它们指向的数据不能直接取消引用(这是合乎逻辑的,因为我们没有要取消引用的类型),因此我们总是必须将 void 指针中的地址转换为在取消引用之前指向具体数据类型的其他指针类型。
空指针称为通用指针。我想用一个示例 pthread 场景来解释。
线程函数的原型为
void *(*start_routine)(void*)
pthread API 设计者考虑了线程函数的参数和返回值。如果这些东西是通用的,我们可以在作为参数发送时将类型转换为 void*。类似地,可以从 void* 中检索返回值(但我从未使用过线程函数的返回值)。
void *PrintHello(void *threadid)
{
long tid;
// ***Arg sent in main is retrieved ***
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
//*** t will be type cast to void* and send as argument.
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
C11 标准 (n1570) §6.2.2.3 al1 p55 说:
指向的指针
void
可以转换为指向任何对象类型的指针或从指向任何对象类型的指针转换。指向任何对象类型的指针都可以转换为指向 void 的指针并再次返回;结果应与原始指针比较。
您可以使用此通用指针来存储指向任何对象类型的指针,但您不能对它使用通常的算术运算,也不能尊重它。
avoid*
是一个指针,但它指向的类型是未指定的。当您将 void 指针传递给函数时,您需要知道它的类型,以便稍后在函数中将其转换回正确的类型以使用它。您将看到pthreads
使用与您的示例中的原型完全相同的函数的示例,这些原型用作线程函数。然后,您可以将该void*
参数用作指向您选择的通用数据类型的指针,然后将其转换回该类型以在您的线程函数中使用。使用 void 指针时需要小心,因为除非您返回到其真实类型的指针,否则您最终可能会遇到各种问题。
该函数接受一个指向任意类型的指针并返回一个这样的类型。
这意味着指针,您可以使用此链接获取有关指针的更多信息 http://www.cprogramming.com/tutorial/c/lesson6.html