Co oznacza void* i jak go używać?
Dzisiaj, kiedy czytałem cudzy kod, zobaczyłem coś w stylu void *func(void* i);
, co to void*
oznacza tutaj dla nazwy funkcji i dla typu zmiennej, odpowiednio?
Ponadto, kiedy musimy używać tego rodzaju wskaźnika i jak go używać?
10 answers
Wskaźnik do void
jest typem wskaźnika "generycznego". A void *
może być przekonwertowany na dowolny inny typ wskaźnika bez wyraźnego oddania. Nie możesz dereferować void *
ani arytmetyki wskaźnika; musisz najpierw przekonwertować wskaźnik na kompletny typ danych.
void *
jest często używany w miejscach, w których musisz być w stanie pracować z różnymi typami wskaźników w tym samym kodzie. Jednym z najczęściej cytowanych przykładów jest funkcja biblioteczna qsort
:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
base
jest adres tablica, nmemb
jest liczbą elementów w tablicy, {[11] } jest wielkością każdego elementu, a {[12] } jest wskaźnikiem do funkcji porównującej dwa elementy tablicy. Nazywa się 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 tablicowe iArr
, dArr
, i {[15] } są domyślnie konwertowane z typów tablic na typy wskaźników w wywołaniu funkcji, a każdy z nich jest domyślnie konwertowany z " wskaźnik do int
/double
/long
" do " wskaźnik do void
".
Funkcje porównawcze wyglądałyby jak coś like:
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 *
, qsort
może pracować z tablicami dowolnego typu.
Wadą używania void *
jest to, że wyrzuca się zabezpieczenie typu przez okno i w nadjeżdżający z naprzeciwka ruch. Nie ma nic, co uchroni Cię przed użyciem niewłaściwej procedury porównywania: {]}
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareInt
oczekuje, że jego argumenty będą wskazywać na int
s, ale w rzeczywistości działa z double
s. nie ma sposobu, aby złapać ten problem podczas kompilacji; po prostu skończysz z missorted array.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 22:36:26
Użycie void * oznacza, że funkcja może przyjmować wskaźnik, który nie musi być określonym typem. Na przykład, w funkcjach gniazd, masz
send(void * pData, int nLength)
Oznacza to, że można go wywołać na wiele sposobów, na przykład
char * data = "blah";
send(data, strlen(data));
POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:20:26
C jest niezwykły pod tym względem. Można powiedzieć void
czy nicość void*
jest wszystkim (może być wszystkim).
void *
jest wskaźnikiem do jakiejś lokalizacji. To, jak "zinterpretować", pozostaje użytkownikowi.
Jest to jedyny sposób, aby mieć nieprzezroczyste typy w C. bardzo widoczne przykłady można znaleźć np. w glib lub bibliotekach ogólnej struktury danych. Jest traktowany bardzo szczegółowo w " interfejsach C i wdrożenia".
Proponuję przeczytać cały rozdział i spróbować zrozumieć pojęcie wskaźnika, aby "dostać to".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-22 09:59:10
void*
Jest 'wskaźnikiem do pamięci bez założeń jaki typ jest tam przechowywany'. Możesz użyć na przykład, jeśli chcesz przekazać argument funkcji i ten argument może być kilku typów, a w funkcji będziesz obsługiwał każdy typ.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:17:05
Możesz rzucić okiem na ten artykuł o wskaźnikach http://www.cplusplus.com/doc/tutorial/pointers/{[2] } i przeczytaj rozdział: void pointers .
To również działa dla języka C.
Wskaźnik typu void jest specjalnym typem wskaźnika. W C++, void reprezentuje Brak Typu, więc wskaźniki void są wskaźnikami, które wskaż wartość, która nie ma Typu (A więc również nieokreślonego długość i nieokreślone właściwości dereferencyjne).
Pozwala to na wskazanie dowolnego typu danych z liczby całkowitej wartość lub zmiennoprzecinkowa do ciągu znaków. Ale w zamian mają wielkie ograniczenie: dane przez nie wskazywane nie mogą być bezpośrednio dereferenced (co jest logiczne, ponieważ nie mamy typu do dereferencji do), i z tego powodu zawsze będziemy musieli oddać adres w wskaźnik void do innego typu wskaźnika, który wskazuje na konkretny typ danych przed jego odwołaniem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:19:34
Wskaźnik void jest znany jako wskaźnik ogólny. Chciałbym wyjaśnić przykładowym scenariuszem pthread.
Funkcja wątku będzie miała prototyp jako
void *(*start_routine)(void*)
Projektanci API pthread rozważali wartości argumentu i zwracania funkcji wątku. Jeśli te rzeczy są generyczne, możemy wpisać cast do void * podczas wysyłania jako argument. podobnie wartość zwracana może być pobrana z void*(ale nigdy nie używałem wartości zwracanych z funkcji wątku).
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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:38:23
C11 standard (n1570) §6.2.2.3 al1 p55 mówi:
Wskaźnik do
void
może być zamieniony na lub ze wskaźnika na dowolny obiekt Typ. Wskaźnik do dowolnego typu obiektu może być konwertowany na wskaźnik do void I back again; wynik jest równy oryginałowi pointer.
Możesz użyć tego ogólnego wskaźnika do przechowywania wskaźnika do dowolnego typu obiektu, ale nie możesz używać z nim zwykłych operacji arytmetycznych i nie możesz go ignorować.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:21:42
A void*
jest wskaźnikiem, ale typ, na który wskazuje, jest nieokreślony. Kiedy przekazujesz wskaźnik void do funkcji, musisz wiedzieć, jaki był jej typ, aby później przywrócić go do tego poprawnego typu w funkcji, aby go użyć. Zobaczysz przykłady w pthreads
, które używają funkcji z dokładnie prototypem w twoim przykładzie, które są używane jako funkcja wątku. Następnie możesz użyć argumentu void*
jako wskaźnika do wybranego ogólnego typu danych, a następnie przenieść go z powrotem do tego typu użyj funkcji wątku. Musisz być ostrożny, gdy używasz void pointers, ponieważ jeśli nie powrócisz do wskaźnika jego prawdziwego typu, możesz skończyć z różnego rodzaju problemami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:21:42
Funkcja pobiera wskaźnik do dowolnego typu i zwraca taki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:18:29
Oznacza wskaźnik możesz użyć tego linku, aby uzyskać więcej informacji o wskaźniku http://www.cprogramming.com/tutorial/c/lesson6.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 08:21:57