void *是什么意思以及如何使用它?

今天当我读别人的代码时,我看到了像void *func(void* i); ,这个void*分别在函数名和variablestypes中是什么意思?

另外,我们什么时候需要使用这种指针以及如何使用它?

指向void的指针是“通用”指针types。 一个void *可以被转换为任何其他的指针types而不需要显式的转换。 你不能解引用一个void *或者做指针运算。 您必须首先将其转换为指向完整数据types的指针。

它被用在你需要能够在同一代码中使用不同指针types的地方。 一个常见的例子是库函数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); 

数组expression式iArrdArrlArr从数组types隐式转换为函数调用中的指针types,并且每个都从“指向int / double / long ”隐式转换为“ void to pointer”。

比较函数看起来像这样:

 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可以处理任何types的数组。

使用void *的缺点是你把types安全性扔出窗外,迎面而来的交通。 没有什么可以保护您使用错误的比较例程:

 qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt); 

compareInt期望它的参数指向int s,但实际上是使用double s。 编译时无法解决这个问题。 你只是结束了一个错误sorting的数组。

使用void *意味着函数可以接受一个不需要是特定types的指针。 例如,在套接字函数中,你有

 send(void * pData, int nLength) 

这意味着你可以用很多方式来调用它,例如

 char * data = "blah"; send(data, strlen(data)); POINT p; px = 1; py = 2; send(&p, sizeof(POINT)); 

你可以看看这篇关于指针的文章,阅读下面的章节: void pointers

这也适用于C语言。

voidtypes的指针是一种特殊types的指针。 在C ++中,void表示缺lesstypes,所以void指针指向的是没有types的值(因此也有未确定的长度和未确定的取消引用属性)。

这允许void指针指向任何数据types,从整数值或浮点数到string。 但是作为交换,它们有一个很大的限制:它们指向的数据不能被直接解引用(这是合乎逻辑的,因为我们没有types可以解引用),所以我们总是要把地址放在void指针中一些其他指针types指向一个具体的数据types之前解除引用。

C在这方面非常出色。 人们可以说无效是无效无效*是一切(可以是无用的)

这只是这个微小的*,这是不同的。

雷内已经指出了。 void *是指向某个位置的指针。 什么是如何“解释”是留给用户的。

这是在C中使用不透明types的唯一方法。非常突出的例子可以在glib或通用数据结构库中find。 在“C接口和实现”中处理得非常详细。

我build议你阅读完整的章节,并尝试理解“获取它”的指针的概念。

 void* 

是一个“内存指针,没有任何假设存储的types”。 例如,你可以使用,如果你想传递一个参数的函数,这个参数可以有几种types,在函数中,你将处理每种types。

void*是一个指针,但它指向的types是未指定的。 当你传递一个void指针给一个函数时,你将需要知道它的types是什么types,以便在函数中稍后将其转换回正确的types来使用它。 你将在pthreads看到使用函数的示例,这些函数与您的示例中的原型完全一样,被用作线程函数。 然后,您可以使用void*参数作为指向您所select的通用数据types的指针,然后将其转换回该types以在您的线程函数中使用。 在使用void指针的时候需要小心,除非你回到一个真正的types指针,否则你可能会遇到各种各样的问题。

C11标准(n1570)§6.2.2.3al1 p55说:

指向void的指针可以被转换为或指向任何对象types的指针。 指向任何对象types的指针都可以被转换为void和指向的指针; 结果应该等于原始指针。

你可以使用这个generics指针来存储一个指向任何对象types的指针,但是你不能对它使用通常的算术运算,而且你也不能使用它。

一个void指针被称为generics指针。 我想用一个示例pthread场景来解释。

线程函数将具有原型

 void *(*start_routine)(void*) 

pthread APIdevise者考虑了线程函数的参数和返回值。 如果这些东西都是通用的,那么我们可以在发送参数的时候将types转换为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); } 

该函数需要一个指向任意types的指针并返回一个。

这意味着你可以使用这个链接来获取更多关于指针的信息http://www.cprogramming.com/tutorial/c/lesson6.html

函数名称之前的VOID意味着它不返回任何东西。 只是做一些东西。 另一方面VOID作为参数使它成为通用函数,可以接受任何types的参数。 但是你必须提供这个参数的大小的函数。