Từ câu trả lời này về Kỹ thuật phần mềm, void
được xử lý đặc biệt tùy thuộc vào cách sử dụng. Trong C
và C++
, void
được sử dụng để biểu thị sự vắng mặt của một loại dữ liệu, trong khi đó void *
được sử dụng để chỉ ra một con trỏ trỏ đến một số dữ liệu / không gian trong bộ nhớ không có loại. void *
không thể tự hủy đăng ký và phải được chuyển sang loại khác trước. Diễn viên này không cần phải rõ ràng C
, nhưng phải rõ ràng trong C++
. (Đây là lý do tại sao chúng tôi không bỏ giá trị trả về của malloc void *
.)
Khi được sử dụng với chức năng như một tham số, void
có nghĩa là hoàn toàn không có bất kỳ tham số nào và là tham số duy nhất được phép. Cố gắng sử dụng void như một loại biến hoặc bao gồm các đối số khác dẫn đến lỗi trình biên dịch:
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);
^
Tương tự không thể khai báo một biến có kiểu 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
như một giá trị trả về cho một hàm cho biết sẽ không có dữ liệu nào được trả về. Vì không thể khai báo một biến kiểu void
, nên không thể bắt được giá trị trả về của void
hàm, ngay cả với một con trỏ 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);
^ ~~~~~~
Các typless void *
là một trường hợp khác nhau. Một con trỏ void chỉ ra một con trỏ tới một vị trí trong bộ nhớ, nhưng không chỉ ra loại dữ liệu tại con trỏ đó. (Đây là cách được sử dụng để đạt được tính đa hình trong C , chẳng hạn như với hàm qsort () .) Những con trỏ này có thể khó sử dụng, tuy nhiên, rất dễ để vô tình chuyển chúng sang loại sai. Mã dưới đây sẽ không ném bất kỳ lỗi biên dịch nào C
, nhưng dẫn đến hành vi không xác định:
#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);
}
Các mã sau đây, tuy nhiên, là hoàn toàn hợp pháp; truyền đến và từ một con trỏ trống không bao giờ thay đổi giá trị mà nó giữ.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47.200000
Là một tham số chức năng, void *
chỉ ra rằng loại dữ liệu tại con trỏ bạn truyền vào không được biết, và người lập trình, tùy thuộc vào bạn để xử lý chính xác bất cứ thứ gì ở vị trí bộ nhớ đó. Là một giá trị trả về, void *
chỉ ra rằng loại dữ liệu được trả về không được biết hoặc không có lỗi và phải được chương trình xử lý.
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
trong một nguyên mẫu hàm có nghĩa là "không có dữ liệu" và cho biết không có giá trị trả về hoặc không có tham số, void *
trong một nguyên mẫu hàm có nghĩa là "dữ liệu tại con trỏ mà hàm này được cung cấp không có kiểu đã biết" và chỉ ra một tham số hoặc giá trị trả về con trỏ của nó phải được chuyển sang một loại khác trước khi dữ liệu tại con trỏ có thể được sử dụng.