С этого ответа на Software Engineering, void
рассматривается специально в зависимости от того, как он используется. В C
и C++
, void
используется для указания на отсутствие типа данных, в то время void *
используется для обозначения указатель , который указывает на некоторые данные / пространства в памяти , которая не имеет тип. void *
не может быть разыменовано само по себе, и должно быть сначала приведено к другому типу. Это приведение не обязательно должно быть явным в C
, но должно быть явным в C++
. (Вот почему мы не приводим возвращаемое значение malloc void *
.)
При использовании с функцией в качестве параметра void
означает полное отсутствие каких-либо параметров и является единственным допустимым параметром. Попытка использовать void как тип переменной или включить другие аргументы приводит к ошибке компилятора:
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);
^
Аналогичным образом невозможно объявить переменную с типом 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;
void
как возвращаемое значение для функции указывает, что данные не будут возвращены. Поскольку невозможно объявить переменную типа void
, невозможно поймать возвращаемое значение void
функции, даже с указателем void.
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);
^ ~~~~~~
Несовершенство void *
- это другой случай. Пустой указатель указывает указатель на местоположение в памяти, но не указывает тип данных в этом указателе. (Это используется для достижения полиморфизма в C , например, с помощью функции qsort () .) Однако эти указатели могут быть сложны в использовании, поскольку очень легко случайно привести их к неправильному типу. Приведенный ниже код не будет выдавать никаких ошибок компилятора C
, но приведет к неопределенному поведению:
#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);
}
Следующий код, однако, совершенно легален; приведение к пустому указателю и обратно никогда не изменяет его значение.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47.200000
Как параметр функции void *
указывает, что тип данных в указателе, который вы передаете, неизвестен, и вы, программист, должны правильно обрабатывать все, что находится в этом месте памяти. В качестве возвращаемого значения void *
указывает, что тип возвращаемых данных неизвестен или не имеет типов и должен обрабатываться программой.
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
в прототипе функции означает «нет данных» и указывает на отсутствие возвращаемого значения или параметров, void *
в прототипе функции означает «данные в указателе, которому дана эта функция, не имеют известного типа» и указывают параметр или возвращаемое значение чей указатель должен быть приведен к другому типу, прежде чем данные в указателе могут быть использованы.