Wskaźnik do voidjest „ogólnym” typem wskaźnika. A void *można przekonwertować na dowolny inny typ wskaźnika bez jawnego rzutowania. Nie można wyłuskać void *ani wykonać arytmetyki wskaźnikowej; musisz najpierw przekonwertować go na wskaźnik do pełnego typu danych.
void *jest często używany w miejscach, w których musisz mieć możliwość pracy z różnymi typami wskaźników w tym samym kodzie. Jednym z często cytowanych przykładów jest funkcja biblioteki qsort:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
baseto adres tablicy, nmembto liczba elementów w tablicy, sizeto rozmiar każdego elementu i comparjest wskaźnikiem do funkcji, która porównuje dwa elementy tablicy. Nazywa się to tak:
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);
Wyrażenia tablicy iArr, dArri lArrsą pośrednio przekształcony z typów tablicowe do rodzaju wskaźnika w wywołania funkcji, a każda z nich jest w sposób dorozumiany przekształcony z „wskaźnika do int/ double/ long” do „do wskaźnika void”.
Funkcje porównawcze wyglądałyby mniej więcej tak:
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;
}
Akceptując void *, qsortmożna pracować z tablicami dowolnego typu.
Wadą używania void *jest to, że wyrzucasz typ bezpieczeństwa przez okno i zbliżasz się do ruchu. Nie ma nic, co mogłoby Cię chronić przed użyciem niewłaściwej procedury porównywania:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareIntoczekuje, że jego argumenty będą wskazywać na ints, ale w rzeczywistości pracuje z doubles. Nie ma możliwości wychwycenia tego problemu w czasie kompilacji; po prostu skończysz z nieprawidłową tablicą.