З цієї відповіді на програмування інженерії 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 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 *
у прототипі функції означає "дані вказівника, яким ця функція задана, не мають відомого типу" і вказують параметр або повернене значення чий вказівник повинен бути переданий на інший тип, перш ніж дані вказівника можуть бути використані.