【问题标题】:What does void* mean and how to use it?void* 是什么意思以及如何使用它?
【发布时间】:2012-07-22 12:43:36
【问题描述】:

今天在看别人的代码时,看到void *func(void* i);这样的东西,这个void*在这里分别代表函数名和变量类型是什么意思?

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

【问题讨论】:

标签: c


【解决方案1】:

指向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);

数组表达式iArrdArrlArr在函数调用中从数组类型隐式转换为指针类型,每个表达式都从“指向int/double/@的指针隐式转换” 987654337@" 到 "指向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 期望它的参数指向ints,但实际上正在使用doubles。没有办法在编译时发现这个问题;你只会得到一个错误的数组。

【讨论】:

  • 实际上并不能保证 void* 可以转换为函数指针。但是对于数据指针,您所说的成立。
  • 在 void 指针可用之前,使用了“char *”。但 void 更好,因为它实际上不能用于直接更改任何内容。
【解决方案2】:

使用 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));

【讨论】:

  • 所以这很像其他语言中的泛型,但没有类型检查,对吧?
  • 我想应该是类似的,但是由于没有类型检查,出错可能会导致非常奇怪的结果或导致程序彻底崩溃。
【解决方案3】:

C 在这方面非常出色。可以说void 是虚无void* 是一切(可以是一切)。

正是这个小小的* 与众不同。

Rene 指出了这一点。 void * 是指向某个位置的指针。如何“解释”的内容留给用户。

这是在 C 中使用不透明类型的唯一方法。可以在 glib 或通用数据结构库中找到非常突出的示例。在“C 接口和实现”中对其进行了非常详细的处理。

我建议你阅读完整的章节并尝试理解“get it”指针的概念。

【讨论】:

    【解决方案4】:
    void*
    

    是一个“指向内存的指针,不假设存储的是什么类型”。 例如,您可以使用,如果您想将参数传递给函数,并且该参数可以是多种类型,并且在函数中您将处理每种类型。

    【讨论】:

      【解决方案5】:

      您可以查看这篇关于指针http://www.cplusplus.com/doc/tutorial/pointers/ 的文章并阅读章节:void pointers

      这也适用于 C 语言。

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

      这允许 void 指针指向任何数据类型,从整数 一个字符串的值或浮点数。但作为交换,他们有 一个很大的限制:他们指向的数据不能直接 取消引用(这是合乎逻辑的,因为我们没有要取消引用的类型 to),因此我们将始终必须将地址转换为 指向某个具体的其他指针类型的 void 指针 取消引用之前的数据类型。

      【讨论】:

        【解决方案6】:

        空指针被称为通用指针。我想用一个示例 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);
        }
        

        【讨论】:

        【解决方案7】:

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

        指向void 的指针可以转换为指向任何对象的指针或从指向任何对象的指针转换 类型。指向任何对象类型的指针都可以转换为指向 无效并再次返回;结果应与原始结果相同 指针。

        您可以使用此通用指针来存储指向任何对象类型的指针,但您不能对它使用通常的算术运算,也不能尊重它。

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

            该函数接受一个指向任意类型的指针并返回一个这样的类型。

            【讨论】:

              【解决方案10】:

              它表示指针,您可以使用此链接获取有关指针的更多信息 http://www.cprogramming.com/tutorial/c/lesson6.html

              【讨论】:

                猜你喜欢
                • 2012-09-12
                • 2010-11-22
                • 2015-02-02
                • 2016-02-26
                • 2016-02-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-21
                相关资源
                最近更新 更多