Khoảng trống có nghĩa là gì trong C, C ++ và C #?


170

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.


2
Câu hỏi này kết hợp 3 ngôn ngữ ... câu hỏi kế thừa đó nên được chia thành 3 câu hỏi khác nhau.
Stargateur

Câu trả lời:


225

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:

  1. Đối số chức năng: int myFunc(void) - chức năng không có gì.

  2. Hàm trả về giá trị: void myFunc(int) - hàm trả về không có gì

  3. 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.


7
khoảng trống trong danh sách đối số là tùy chọn trong C ++, xem stackoverflow.com/questions/416345/ trên
Daniel Earwicker

1
Tôi sẽ sử dụng "không loại" thay vì "không có kích thước"
Kjetil Joergensen

@Earwicker và kjetijor, cả hai điểm tốt mà tôi đã tranh luận, nhưng tâm trí không ngủ của tôi cần sự giúp đỡ;) Cảm ơn.
Gerald

9
Không đồng ý, nhưng việc sử dụng thêm khoảng trống nằm trong thủ thuật "cast to void" để triệt tiêu các cảnh báo cho các giá trị không sử dụng. Hơi khó khăn một chút vì nó không thực sự tương ứng với cách trình biên dịch diễn giải mọi thứ, nhưng bạn có thể hiểu điều đó có nghĩa là "Tôi đang sử dụng giá trị này để không làm gì cả".
Steve Jessop

22
Trong C ++, void trong danh sách đối số là tùy chọn. Tuy nhiên, trong C, nó KHÔNG phải là tùy chọn: foo () có nghĩa là nó nhận bất kỳ số lượng tham số thuộc bất kỳ loại nào, trong khi foo (void) có nghĩa là nó không có tham số nào.
Adam Rosenfield

33

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ặt
  • void f(P)- Giá trị trả lại vắng mặt
  • void *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ặt

Con cháu C khác sử dụng nó cho những thứ khác. Các Dngô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

4
Không gì (void)plà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ó."
Yashas

@Yashas Nếu bất cứ ai cũng nhầm lẫn về (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 .
Arnie97

14

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 */;
}

13

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. Khá nhiều phù hợp với cách sử dụng điển hình của từ void trong tiếng Anh.


4

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 voidtừ 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ị.


3

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ữ.



2

Ba trường hợp sử dụng cho void:

  1. 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.

  2. 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.

  3. 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.


2

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.


Chỉ cần một lưu ý liên quan đến câu cuối cùng của bạn - hãy nhớ rằng điều đó chỉ đúng với các ngôn ngữ được gõ tĩnh. Các ngôn ngữ được gõ động không cần khoảng trống vì các phương thức của chúng có thể chỉ đơn giản là không trả về bất cứ thứ gì - "khoảng trống" được ngụ ý bởi việc thiếu bất cứ thứ gì khác được trả về.
Đánh dấu vào

Sửa lỗi cho nhận xét cuối cùng của tôi - Tôi muốn nói đoạn cuối (không phải câu).
Đánh dấu vào

1

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.


0

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.


0

Void là một loại không đầy đủ, theo định nghĩa, không thể là một giá trị. Điều đó có nghĩa là nó không thể được gán một giá trị.

Vì vậy, nó cũng không thể giữ bất kỳ giá trị.


-1

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


-1

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ữ.


-1

Void tương đương với Sub của Visual Basic.


Chỉ là một loại trả lại. Tôi có thể nghĩ ra thêm ba cách sử dụng void: void argument (hàm không có gì), void con trỏ (không có loại con trỏ được chỉ định) và void phôi (loại bỏ giá trị).
c4757p
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.