今天当我阅读别人的代码时,我看到了类似void *func(void* i);
的内容,这里void*
分别代表函数名和变量类的含义是什么?
另外,我们何时需要使用这种指针以及如何使用它?
答案 0 :(得分:157)
指向void
的指针是“通用”指针类型。可以将void *
转换为任何其他指针类型,而无需显式转换。你不能取消引用void *
或用它做指针算术;您必须先将其转换为指向完整数据类型的指针。
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
被隐式地从数组类型转换为函数调用中的指针类型,并且每个都隐式地从“指针转换为{{1 }} / 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
。在编译时没有办法解决这个问题;你只需要一个错误的阵列。
答案 1 :(得分:22)
使用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));
答案 2 :(得分:6)
只是这个微小的*才能与众不同。
雷恩指出了这一点。 void *是指向某个位置的指针。有什么“解释”是留给用户的。这是在C中使用不透明类型的唯一方法。可以在glib或通用数据结构库中找到非常突出的示例。它在“C接口和实现”中得到了非常详细的处理。
我建议你阅读完整的章节并尝试理解指向“获取它”的指针。
答案 3 :(得分:3)
void*
是一个'指向内存的指针,没有假设存储了什么类型'。 例如,您可以使用如果要将参数传递给函数,并且此参数可以是多种类型,并且在函数中您将处理每种类型。
答案 4 :(得分:3)
您可以查看有关指针http://www.cplusplus.com/doc/tutorial/pointers/的本文,并阅读章节:无效指针。
这也适用于C语言。
指针的void类型是一种特殊类型的指针。在C ++中,无效 表示缺少类型,因此void指针是指针 指向没有类型的值(因此也是未确定的 长度和未确定的解引用属性)。
这允许void指针从整数指向任何数据类型 value或浮点到字符串。但作为交换,他们有 一个很大的限制:他们指出的数据不能直接 dereferenced(这是合乎逻辑的,因为我们没有要取消引用的类型 由于这个原因,我们总是要把地址输入 void指针指向一个指向具体的其他指针类型 解除引用之前的数据类型。
答案 5 :(得分:3)
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);
}
答案 6 :(得分:1)
void*
是一个指针,但它指向的类型是未指定的。当您将void指针传递给函数时,您需要知道它的类型是什么,以便稍后在函数中将其强制转换为正确的类型以使用它。您将看到pthreads
中的示例,这些示例使用的函数与示例中用作线程函数的原型完全相同。然后,您可以使用void*
参数作为指向您选择的通用数据类型的指针,然后将其强制转换为该类型以在您的线程函数中使用。在使用void指针时你需要小心,除非你回到它的真实类型的指针,你最终会遇到各种各样的问题。
答案 7 :(得分:1)
C11标准(n1570)§6.2.2.3al1p55说:
指向
void
的指针可以转换为指向任何对象的指针 类型。指向任何对象类型的指针可以转换为指向 无效又回来;结果应与原始数据相等 指针。
您可以使用此通用指针存储指向任何对象类型的指针,但您不能使用它的常规算术运算,并且您不能将它推迟。
答案 8 :(得分:0)
该函数接受一个指向任意类型的指针并返回一个这样的。
答案 9 :(得分:-1)
它表示指针可以使用此链接获取有关指针的更多信息 http://www.cprogramming.com/tutorial/c/lesson6.html
答案 10 :(得分:-6)
函数名之前的VOID表示它不返回任何内容。只是做一些事情。另一方面,作为参数的VOID使其成为可以接受任何类型参数的通用函数。但是你必须提供具有this参数大小的函数。