关于C#:void *是什么意思,以及如何使用它?


What does void* mean and how to use it?

今天,当我阅读别人的代码时,我看到了类似void *func(void* i);的东西,这个void*在这里分别对函数名和变量类型意味着什么?

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


指向void的指针是"通用"指针类型。 void *可以转换为任何其他指针类型,而无需显式强制转换。您不能取消引用void *或对其进行指针算术;您必须先将其转换为指向完整数据类型的指针。

void *通常用于需要在同一代码中使用不同指针类型的地方。一个经常引用的示例是库函数qsort

1
2
void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

base是数组的地址,nmemb是数组中元素的数量,size是每个元素的大小,compar是指向比较数组中两个元素的函数的指针。它的调用方式如下:

1
2
3
4
5
6
7
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);

数组表达式iArrdArrlArr在函数调用中从数组类型隐式转换为指针类型,并且每个表达式从"指针转换为int / double / long"隐式转换。指向" void的指针"。

比较功能如下所示:

1
2
3
4
5
6
7
8
9
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 *的缺点是您将类型安全性扔出了窗外,迎面而来。没有什么可以防止您使用错误的比较例程:

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

compareInt期望其参数指向int,但实际上与double一起使用。在编译时没有办法解决这个问题。您将得到一个错误排列的数组。


使用void *表示该函数可以采用不需要为特定类型的指针。
例如,在套接字函数中,

1
send(void * pData, int nLength)

这意味着您可以通过多种方式调用它,例如

1
2
3
4
5
6
7
char * data ="blah";
send(data, strlen(data));

POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));


就这一点而言,C非常出色。我们可以说
虚无就是虚无
void *是一切(可以是一切)

只是这个微小的*有所作为。

雷内指出了这一点。无效*是指向某个位置的指针。怎样"解释"什么留给用户。

这是在C中具有不透明类型的唯一方法。可以在glib或常规数据结构库中找到非常突出的示例。在" C接口和实现"中对其进行了非常详细的介绍。

我建议您阅读完整的章节并尝试理解"获取它"的指针的概念。


空指针称为通用指针。我想用一个示例pthread场景来解释。

线程函数的原型为

1
void *(*start_routine)(void*)

pthread API设计人员考虑了线程函数的参数和返回值。如果这些东西是通用的,我们可以在发送参数时将强制类型转换为void *。同样,可以从void *中检索返回值(但是我从未使用过线程函数的返回值)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void *PrintHello(void *threadid)
{
   long tid;

   // ***Arg sent in main is retrieved   ***
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!
"
, 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
"
, rc);
         exit(-1);
      }
   }    
   /* Last thing that main() should do */
   pthread_exit(NULL);
}


您可以在http://www.cplusplus.com/doc/tutorial/pointers/上查看有关指针的本文,并阅读一章:无效指针。

这也适用于C语言。

The void type of pointer is a special type of pointer. In C++, void
represents the absence of type, so void pointers are pointers that
point to a value that has no type (and thus also an undetermined
length and undetermined dereference properties).

This allows void pointers to point to any data type, from an integer
value or a float to a string of characters. But in exchange they have
a great limitation: the data pointed by them cannot be directly
dereferenced (which is logical, since we have no type to dereference
to), and for that reason we will always have to cast the address in
the void pointer to some other pointer type that points to a concrete
data type before dereferencing it.


1
void*

是"在不假设存储哪种类型的情况下指向内存的指针"。
例如,如果要向函数传递参数,则可以使用此参数,该参数可以具有几种类型,在函数中,您将处理每种类型。


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

A pointer to void may be converted to or from a pointer to any object
type. A pointer to any object type may be converted to a pointer to
void and back again; the result shall compare equal to the original
pointer.

您可以使用该通用指针存储指向任何对象类型的指针,但是不能对其使用常规的算术运算,也不能对其进行推论。


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


该函数采用指向任意类型的指针,并返回一个这样的指针。


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


函数名称前的VOID表示它不返回任何内容。只是做一些事情。另一方面,VOID作为参数使它成为通用函数,可以接受任何类型的参数。但是您必须为函数提供此参数的大小。