Tìm cách để có được các nguyên tắc cơ bản về thuật ngữ " void " xuất phát từ đâu và tại sao nó được gọi là void. Mục đích của câu hỏi là hỗ trợ người không có kinh nghiệm về C và đột nhiên nhìn vào một cơ sở mã dựa trên C.
Tìm cách để có được các nguyên tắc cơ bản về thuật ngữ " void " xuất phát từ đâu và tại sao nó được gọi là void. Mục đích của câu hỏi là hỗ trợ người không có kinh nghiệm về C và đột nhiên nhìn vào một cơ sở mã dựa trên C.
Câu trả lời:
Về cơ bản nó có nghĩa là "không có gì" hoặc "không có loại"
Có 3 cách cơ bản mà void được sử dụng:
Đối số chức năng: int myFunc(void)
- chức năng không có gì.
Hàm trả về giá trị: void myFunc(int)
- hàm trả về không có gì
Con trỏ dữ liệu chung: void* data
- 'dữ liệu' là con trỏ tới dữ liệu không xác định và không thể hủy đăng ký
Lưu ý: void
đối số trong hàm là tùy chọn trong C ++, do đó int myFunc()
hoàn toàn giống với int myFunc(void)
và nó bị bỏ lại hoàn toàn trong C #. Nó luôn luôn được yêu cầu cho một giá trị trả lại.
Tôi đã luôn luôn có nghĩa là vắng mặt . Dưới đây là bốn trường hợp trong ngôn ngữ C phù hợp với việc sử dụng vắng mặt này
R f(void)
- Thông số chức năng vắng mặtvoid f(P)
- Giá trị trả lại vắng mặtvoid *p
- Loại của những gì được chỉ ra là vắng mặt(void) p
- Sử dụng giá trị là vắng mặtCon cháu C khác sử dụng nó cho những thứ khác. Các D
ngôn ngữ lập trình sử dụng nó cho trường hợp một initializer là vắng mặt
T t = void;
- Giá trị khởi tạo là vắng mặt(void)p
làm gì? Tôi hoàn toàn không hiểu ý bạn là gì khi "sử dụng giá trị không có."
(void) var;
tuyên bố, tôi đã tìm thấy câu trả lời chi tiết tại stackoverflow.com/q/21045615 .
Có hai cách để sử dụng void:
void foo(void);
hoặc là
void *bar(void*);
Đầu tiên chỉ ra rằng không có đối số nào được thông qua hoặc không có đối số nào được trả về.
Thứ hai nói với trình biên dịch rằng không có loại nào được liên kết với dữ liệu một cách hiệu quả có nghĩa là bạn không thể sử dụng dữ liệu được trỏ đến cho đến khi nó được chuyển sang loại đã biết.
Ví dụ, bạn sẽ thấy void*
được sử dụng rất nhiều khi bạn có một giao diện gọi một hàm có tham số không thể biết trước.
Ví dụ, trong Linux Kernel khi trì hoãn công việc, bạn sẽ thiết lập một chức năng sẽ được chạy sau đó bằng cách cho nó một con trỏ tới chức năng được chạy và một con trỏ tới dữ liệu được truyền cho hàm:
struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data = somedata;
} deferred_work;
Sau đó, một chuỗi nhân đi qua một danh sách các công việc bị trì hoãn và khi nó đến nút này, nó thực thi một cách hiệu quả:
bar(somedata);
Sau đó, trong thanh bạn có:
void bar(void* mydata) {
int *data = mydata;
/* do something with data */;
}
Nó chỉ ra sự vắng mặt của một giá trị trả về trong một hàm.
Một số ngôn ngữ có hai loại chương trình con: thủ tục và chức năng. Các thủ tục chỉ là một chuỗi các hoạt động, trong khi một chức năng là một chuỗi các hoạt động trả về một kết quả.
Trong C và các dẫn xuất của nó, sự khác biệt giữa hai là không rõ ràng. Tất cả mọi thứ về cơ bản là một chức năng. các void
từ khóa chỉ ra rằng nó không phải là một "thực tế" chức năng, vì nó không trả về giá trị.
Hãy nghĩ về void là "cấu trúc trống rỗng". Hãy để tôi giải thích.
Mỗi hàm lấy một chuỗi các tham số, trong đó mỗi tham số có một loại. Trong thực tế, chúng ta có thể gói các tham số thành một cấu trúc, với các khe cấu trúc tương ứng với các tham số. Điều này làm cho mọi hàm có chính xác một đối số. Tương tự, các hàm tạo ra một kết quả, trong đó có một loại. Nó có thể là một boolean, hoặc nó có thể là float hoặc nó có thể là một cấu trúc, chứa một tập hợp các giá trị được gõ khác tùy ý. Nếu chúng ta muốn một languge có nhiều giá trị trả về, thật dễ dàng chỉ cần nhấn mạnh rằng chúng được đóng gói thành một cấu trúc. Trong thực tế, chúng ta luôn có thể nhấn mạnh rằng một hàm trả về một cấu trúc. Bây giờ mọi hàm đều lấy chính xác một đối số và tạo ra chính xác một giá trị.
Bây giờ, điều gì xảy ra khi tôi cần một hàm tạo ra giá trị "không"? Chà, xem xét những gì tôi nhận được khi tôi tạo một cấu trúc với 3 vị trí: nó chứa 3 giá trị. Khi tôi có 2 vị trí, nó chứa hai giá trị. Khi nó có một khe, một giá trị. Và khi nó có các vị trí 0, nó giữ ... uh, giá trị 0 hoặc "không" giá trị ". Vì vậy, tôi có thể nghĩ về một hàm trả về khoảng trống là trả về một cấu trúc không chứa giá trị. Thậm chí bạn có thể quyết định rằng" void " chỉ là một từ đồng nghĩa cho loại được biểu thị bằng cấu trúc trống, chứ không phải là một từ khóa trong ngôn ngữ (có thể nó chỉ là một loại được xác định trước :)
Tương tự, tôi có thể nghĩ về một hàm không yêu cầu giá trị nào khi chấp nhận một cấu trúc trống, ví dụ: "void".
Tôi thậm chí có thể thực hiện ngôn ngữ lập trình của mình theo cách này. Truyền một giá trị void chiếm 0 byte, vì vậy việc chuyển các giá trị void chỉ là trường hợp đặc biệt để chuyển các giá trị khác có kích thước tùy ý. Điều này giúp trình biên dịch dễ dàng xử lý kết quả hoặc đối số "void". Bạn có thể muốn một tính năng ngôn ngữ có thể ném kết quả chức năng đi; trong C, nếu bạn gọi hàm kết quả không trống foo trong câu lệnh sau: foo (...); trình biên dịch biết rằng foo tạo ra một kết quả và chỉ cần bỏ qua nó. Nếu void là một giá trị, thì điều này hoạt động hoàn hảo và bây giờ "thủ tục" (chỉ là tính từ cho một hàm có kết quả void) chỉ là trường hợp đặc biệt tầm thường của các hàm chung.
Vô hiệu * là một chút buồn cười. Tôi không nghĩ các nhà thiết kế C nghĩ về khoảng trống theo cách trên; họ chỉ cần tạo một từ khóa. Từ khóa đó có sẵn khi ai đó cần một điểm đến một loại tùy ý, do đó void * là thành ngữ trong C. Nó thực sự hoạt động khá tốt nếu bạn diễn giải void là một cấu trúc trống. Một con trỏ void * là địa chỉ của một nơi đã đặt cấu trúc trống đó.
Chuyển từ void * sang T * cho các loại T khác, cũng hoạt động với phối cảnh này. Các phôi con trỏ là một mánh gian lận hoàn toàn hoạt động trên hầu hết các kiến trúc phổ biến để lợi dụng thực tế là nếu một loại hợp chất T có một phần tử với kiểu con S được đặt vật lý ở đầu T trong bố trí lưu trữ của nó, sau đó chuyển S * thành T * và ngược lại sử dụng cùng một địa chỉ máy vật lý có xu hướng hoạt động, vì hầu hết các con trỏ máy có một đại diện duy nhất. Việc thay thế loại S bằng khoảng trống loại cho hiệu quả chính xác tương tự, và do đó, việc chuyển sang / từ void * hoạt động.
Ngôn ngữ lập trình PARLANSE thực hiện các ý tưởng trên khá chặt chẽ. Chúng tôi đã ủng hộ thiết kế của nó và không chú ý đến "void" như một kiểu trả về và do đó có các từ khóa langauge cho thủ tục. Đây chủ yếu chỉ là một thay đổi cú pháp đơn giản, nhưng đó là một trong những điều bạn không có được khi bạn nhận được một mã cơ thể lớn làm việc bằng ngôn ngữ.
Trong c # bạn sẽ sử dụng từ khóa void để chỉ ra rằng một phương thức không trả về giá trị:
public void DoSomeWork()
{
//some work
}
Ba trường hợp sử dụng cho void:
Chữ ký chức năng. void foo(int bar)
không trả về một giá trị. int bar(void)
không lấy bất kỳ tham số nào nhưng điều này thường được thể hiện với danh sách đối số trống : int bar()
. Cách sử dụng từ khóa void ở đây tương ứng với nghĩa của nó trong tiếng Anh.
Con trỏ loại trên cùng chung trỏ void *
đến dữ liệu không xác định và không thể hủy đăng ký. Ở đây ý nghĩa của void khác với các nghĩa khác của void: loại phổ quát so với không loại.
Trong các phôi như (void) new Foo(this)
để biểu thị rằng giá trị trả lại được cố tình vứt đi. Ở đây việc sử dụng từ khóa cũng phù hợp với ý nghĩa của nó trong tiếng Anh.
Các trường hợp 1 và 2 đã được @Gerald bao trả nhưng trường hợp 3 vẫn chưa được giải quyết.
Nếu bạn đang giải thích khái niệm này cho người mới bắt đầu, có thể hữu ích khi sử dụng một sự tương tự. Việc sử dụng void trong tất cả các trường hợp này có ý nghĩa tương tự với một trang trong một cuốn sách có các từ sau, "Trang này để trống có chủ ý." Đó là để phân biệt trình biên dịch giữa một cái gì đó nên được gắn cờ là một lỗi, so với một loại cố ý để trống vì đó là hành vi bạn muốn.
Nó luôn xuất hiện trong mã nơi thông thường bạn sẽ thấy một loại xuất hiện, chẳng hạn như loại trả về hoặc loại con trỏ. Đây là lý do tại sao trong C #, void ánh xạ tới một loại CLR thực tế, System.Void vì bản thân nó là một loại.
Một số ngôn ngữ lập trình không bao giờ phát triển khái niệm về khoảng trống, giống như một số nền văn hóa của con người không bao giờ phát minh ra khái niệm số 0. Void đại diện cho sự tiến bộ tương tự trong ngôn ngữ lập trình như khái niệm số 0 đại diện cho ngôn ngữ của con người.
Nó có nghĩa là "không có giá trị". Bạn sử dụng void để chỉ ra rằng một hàm không trả về giá trị hoặc nó không có tham số hoặc cả hai. Nó rất phù hợp với cách sử dụng từ void trong tiếng Anh thông thường.
Vô hiệu không nên nhầm lẫn với null. Null có nghĩa là biến có địa chỉ trên stack, giá trị trên heap cho địa chỉ đó trống.
Vô hiệu chỉ được sử dụng trong chữ ký phương thức. Đối với kiểu trả về, điều đó có nghĩa là phương thức sẽ không trả lại bất cứ điều gì cho mã gọi. Đối với tham số có nghĩa là, không có tham số nào được truyền cho phương thức
ví dụ
void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}
Trong C #, chúng ta có thể bỏ qua khoảng trống cho các tham số và có thể viết mã ở trên là:
void MethodThatReturnsAndTakesVoid()
{
// Method body
}
Vô hiệu không nên nhầm lẫn với null. Null có nghĩa là biến có địa chỉ trên stack, giá trị trên heap cho địa chỉ đó trống.
void có nghĩa là bạn sẽ không trả về bất kỳ giá trị nào từ hàm hoặc phương thức
Vô hiệu có nghĩa là không có giá trị cần thiết trong kiểu trả về từ một hàm trong cả ba ngôn ngữ.
Void tương đương với Sub của Visual Basic.