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类型的数组。这样做编译器完全允许,从语法角度没有任何问题,但是你觉得这样对吗?