C void* 指针

C void* 指针

最近在做操作系统实验,发现在定义线程的执行体时,是这么定义的。

void func(void* arg)

当时我就懵了,我们见过各类指针,真没见过void指针,研究一番之后,发现void指针其实非常简单。

void指针可以理解为一种“通用”指针。也就是说可以不通过显式强制类型转换把void *转换为其他任何类型的指针。

但是注意,我们不能对void *指针做任何算术运算,例如上面的指针arg就不可以做如下操作:

arg++;

因为arg是无类型的,编译器不知道要操作多少个字节。

void* 通常用于同一代码需要用到不同类型指针的地方。

一个老生常谈的例子是库函数qsort

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

base是数组的基地址,nmemb是数组元素个数,size是每个元素的大小,compar是函数指针,被指向的函数决定了数组如何排序。

int int_arr[10];
double double_arr[20];
long long_arr[30];
...
qsort(int_arr, sizeof int_arr/sizeof int_arr[0], sizeof int_arr[0], cmp_int);
qsort(double_arr, sizeof double_arr/sizeof double_arr[0], sizeof double_arr[0], cmp_double);
qsort(long_arr, sizeof long_arr/sizeof long_arr[0], sizeof long_arr[0], cmp_long);

在上面的调用中,int_arr、double_arr和long_arr在被传入到qsort的第一个参数时,都隐式地把int *、double *、long *转换为了void指针。

比较函数就会长成下面这个样子

int cmp_int(const void *first, const void *second)
{
  const int *x = first;  // 把void指针转换成int指针
  const int *y = second;

  if (*x > *y) return 1;
  if (*x == *y) return 0;
  return -1;
}

所以可以看到,void*指针使得相同的函数可以作用于不同类型的指针。

但是,这么做非常不安全,例如我们也可以完全做到这个。

qsort(double_arr, sizeof double_arr/sizeof double_arr[0], sizeof double_arr[0], cmp_int);

注意,我们用int的排序函数去排double类型的数组。这样做编译器完全允许,从语法角度没有任何问题,但是你觉得这样对吗?

posted @ 2020-11-10 00:11  scyq  阅读(335)  评论(0编辑  收藏  举报