Z tej odpowiedzi na temat inżynierii oprogramowania void traktujemy specjalnie, w zależności od tego, jak jest używana. W Ci C++, voidsłuży do wskazania nieobecności danego typu danych, podczas gdy void *jest używany do wskazywania wskaźnik, który wskazuje na jakiś danych / przestrzeni w pamięci, które nie mają typu. void *nie można samodzielnie wyrejestrować i należy go najpierw przenieść na inny typ. Ta obsada nie musi być jawna w C, ale musi być jawna w C++. (Właśnie dlatego nie wylewamy wartości zwracanej przez malloc void *).
W przypadku użycia z funkcją jako parametrem voidoznacza całkowity brak jakichkolwiek parametrów i jest jedynym dozwolonym parametrem. Próba użycia void jak typu zmiennej lub dołączenia innych argumentów powoduje błąd kompilatora:
int foo(void, int); //trying to use "void" as a parameter
int bar(void baz); //trying to use "void" as an argument's type
main.c:1:8: error: 'void' must be the first and only parameter if specified
int foo(void, int);
^
main.c:2:14: error: argument may not have 'void' type
int bar(void baz);
^
Podobnie niemożliwe jest zadeklarowanie zmiennej typu void:
int main(void) {
void qux; //trying to create a variable with type void
}
main.c:5:8: error: variable has incomplete type 'void'
void qux;
voidjako wartość zwracana dla funkcji oznacza, że żadne dane nie zostaną zwrócone. Ponieważ nie można zadeklarować zmiennej typu void, nie można uchwycić wartości zwracanej przez voidfunkcję, nawet za pomocą pustego wskaźnika.
void foo(int i) { return; }
int main(void) {
void *j;
j = foo(0);
return 0;
}
main.c:5:5: error: assigning to 'void *' from
incompatible type 'void'
j = foo(0);
^ ~~~~~~
Typless void *to inna sprawa. Pusty wskaźnik wskazuje wskaźnik do lokalizacji w pamięci, ale nie wskazuje rodzaju danych w tym wskaźniku. (Jest to używane do osiągnięcia polimorfizmu w C , na przykład z funkcją qsort ()) . Te wskaźniki mogą być jednak trudne w użyciu, ponieważ bardzo łatwo jest przypadkowo rzucić je na niewłaściwy typ. Poniższy kod nie wrzuci żadnych błędów kompilatora C, ale spowoduje niezdefiniowane zachowanie:
#include <stdio.h>
int main(void) {
double foo = 47.2; //create a double
void *bar = &foo; //create a void pointer to that double
char *baz = bar; //create a char pointer from the void pointer, which
//is supposed to hold a double
fprintf(stdout, "%s\n", baz);
}
Poniższy kod jest jednak całkowicie legalny; rzutowanie na i z pustego wskaźnika nigdy nie zmienia wartości, którą posiada.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47,200000
Jako parametr funkcji void *wskazuje, że typ danych przekazywanych przez wskaźnik nie jest znany i od programisty zależy, czy odpowiednio zajmie się tym, co znajduje się w tym miejscu pamięci. Jako wartość zwracana void *oznacza, że typ zwracanych danych nie jest znany lub jest bez typu i musi być obsługiwany przez program.
int quux(void *); //a function that receives a pointer to data whose type is not known, and returns an int.
void *quuz(int); //a function that receives an int, and returns a pointer to data whose type is not known.
tl; dr void w prototypie funkcji oznacza „brak danych” i wskazuje brak wartości zwracanej lub brak parametrów, void *w prototypie funkcji oznacza „dane wskazane wskaźnikiem tej funkcji nie mają znanego typu” i wskazuje parametr lub wartość zwracaną którego wskaźnik musi być rzutowany na inny typ, zanim będzie można użyć danych na wskaźniku.