2010-01-27 51 views
14

Tại sao không thể gọi hàm không nhận đối số với lệnh gọi hàm làm đối số không trả về bất kỳ giá trị nào (IMHO tương đương với gọi một hàm không có đối số không có đối số).C/C++: Chức năng gọi không có đối số với hàm trả về không có gì

Ví dụ:

void foo(void) {...} 
void bar(void) {...} 

foo(bar()) 

Đừng làm cho tôi sai, tôi biết void không phải là một giá trị và rằng nó không thể bị đối xử như một.

Với logic của tôi, điều đó có ý nghĩa và bạn có thể thực hiện điều đó. Ý tôi là, tại sao không? Bất kỳ lý do nào tại sao điều đó không thể thực hiện được?

+4

Tại sao bạn muốn thực hiện việc này? –

+0

bạn có đang nhầm lẫn các khái niệm về void và null không? –

+16

Bởi vì 'void foo (void)' có nghĩa là "một hàm không nhận đối số", và không phải là "một hàm không có gì là đối số của nó". – jalf

Trả lời

8

Tôi không tin rằng bất kỳ lý do nào mà tôi đã nghe là những lý do hay.

Xem, trong C++, bạn có thể trả về kết quả một void chức năng của:

void foo() { 
    // ... 
} 

void bar() { 
    // ... 
    return foo(); 
} 

Vâng, đó là chính xác giống như:

foo(); 
return; 

nhưng là nhiều phù hợp hơn với lập trình chung chung, do đó bạn có thể làm cho chức năng chuyển tiếp hoạt động mà không phải lo lắng về việc chức năng đang được chuyển tiếp có trả về là void hay không.

Vì vậy, nếu một hệ thống tương tự được áp dụng sao cho trả lại void tạo thành một cuộc gọi vô giá trị trong một kịch bản thành phần chức năng, điều đó có thể làm cho thành phần chức năng trở nên chung chung hơn.

+1

Câu trả lời hay! Tôi thực sự không biết điều đó. Vì vậy, nếu đó là có thể, tại sao shouldnt được những gì tôi đã viết có thể. Đó là về cùng một điều. – George

+2

thực sự nó sẽ, nhưng 'return' là một trường hợp đặc biệt bằng 6.6.3/4:" Một câu lệnh return với biểu thức kiểu "cv void" chỉ có thể được sử dụng trong các hàm có kiểu trả về cv void; được đánh giá ngay trước khi hàm trả về cho người gọi của nó. " – Potatoswatter

+0

Chính xác là quan điểm của tôi. :-) –

0

void không cho phép bạn chỉ định tên đối số, sẽ được yêu cầu để nắm bắt giá trị trả về của hàm đầu tiên, bất kể nó thực sự trả về.

+0

Bạn có thể xây dựng một đối tượng void. 'void (3);' là một cách để không làm gì cả, và phù hợp với ngữ nghĩa của các giá trị chuyển đối số được cho phép chuyển tới các hàm 'void'. – Potatoswatter

1

nó có ý nghĩa (bar không tạo ra gì, foo không tiêu thụ gì cả, do đó foo(bar()) nên được cho phép). OTOH, nó sẽ chỉ tốt để gây nhầm lẫn cho người đọc. nếu bạn muốn là l33t, luôn có các toán tử ,, &&|| để mô phỏng dấu chấm phẩy.

0

Giả sử nó hoạt động. Bạn có thể nghĩ ra một trường hợp giả định duy nhất ở đó

bar(); 
foo(); 

điều chính xác nào không phải là điều dễ đọc và hợp lý hơn?

Đã chỉnh sửa. Vâng vâng. :)

+1

Tôi nghĩ bạn sẽ thấy rằng 'bar(); foo() 'thực sự là thứ tự thực hiện đúng;) –

+0

Thực ra, đó là' bar(); foo(); 'thực hiện chính xác điều tương tự. Các đối số được đánh giá đầy đủ trước khi hàm được gọi. – caf

+0

Hiện tại tôi có nội dung như thế này trong mã của tôi: #define EVAL (f) f (++ evalcounter) Đừng hỏi tôi tại sao tôi sử dụng nó, tôi chỉ phải làm vậy. Thông thường f không có bất kỳ giá trị nào. Tôi chỉ cần thêm số nguyên (toàn cục) này để đếm thứ gì đó. Nó sẽ không được tốt hơn nhiều nếu tôi có một cái gì đó như #define EVAL (f) f (dummy (++ evalcounter))? – George

0

Hiện tại tôi có thứ gì đó như thế này trong mã của tôi: #define EVAL (f) f (++ evalcounter) Không hỏi tôi tại sao tôi sử dụng nó, tôi chỉ phải làm vậy. Thông thường f không có bất kỳ giá trị nào. Tôi chỉ cần thêm số nguyên (toàn cục) này để đếm thứ gì đó. Nó sẽ không được tốt hơn nhiều nếu tôi có một cái gì đó như #define EVAL (f) f (dummy (++ evalcounter))?

Các bạn đã thử các nhà điều hành dấu phẩy:

#define EVAL(f) (++evalcounter, f()) 
+0

Vấn đề là trước hoặc sau EVAL có thể có các biến khác được kết nối với f, vì vậy việc thêm điều này sẽ hủy hoàn toàn kết nối này. – George

+0

Bạn có ý gì khi 'kết nối với f'? Nếu bạn làm 'a = EVAL (f)', đề xuất của tôi sẽ gán giá trị trả về của f cho a. –

+0

@George: Tôi nghĩ bạn nên mở một câu hỏi mới cho điều đó với các ví dụ thực tế về nơi bạn gặp vấn đề. –

3

Bởi vì, theo đoạn 3.9.1/9 của tiêu chuẩn,

Một biểu kiểu void được sử dụng chỉ như một tuyên bố biểu thức (6.2), như một toán hạng của một biểu thức dấu phẩy (5,18), như một thứ hai hoặc thứ ba toán hạng của?: (5.16), làm toán hạng của typeid, hoặc như biểu thức trong câu lệnh trả về (6.6.3) cho hàm với khoảng trống kiểu trả về.

C/C++ không được thiết kế giống như vậy. Bạn làm nhận được return returns_void(); để tối ưu hóa cuộc gọi đuôi, đó là chức năng-ish, phải không? : VP

Edit: Các quy tắc trên vẫn sẽ cho phép bạn gọi takes_void(3) với 3 chuyển đổi sang void. Này bị cấm bởi 8.3.5/2:

Nếu tham số-khai-khoản là rỗng, hàm mất không đối số. Danh sách tham số (void) tương đương với thông số trống danh sách. Ngoại trừ trường hợp đặc biệt này, khoảng trống không được là loại tham số (mặc dù các loại có nguồn gốc từ khoảng trống, chẳng hạn như làm mất hiệu lực *, có thể).

+0

Hehe cũng ít nhất một cái gì đó chúng ta có thể làm :) Btw tôi hiểu rằng c/c + + không được thiết kế cho điều đó. Tôi chỉ muốn nghe ý kiến ​​về những gì tôi nghĩ. Tôi vẫn tin rằng nó sẽ hoàn toàn hợp lý nếu điều này là có thể. – George

+0

@George: Tôi nghĩ phần đáng chú ý là cần phải có bao nhiêu quy tắc để cấm. Có lẽ nó đã có thể trên các trình biên dịch C cũ hơn và ủy ban C++ cảm thấy nó là phong cách nghèo nàn. Có chung chung hơn Ness ngày hôm nay cho một quan điểm khác nhau. – Potatoswatter

2

Nếu danh sách (void) tham số được xử lý thống nhất với tất cả các danh sách tham số khác trong C/C++, ý nghĩa ngữ nghĩa nếu khai thông số như vậy sẽ là "một tham số duy nhất của loại void". Nếu đúng như vậy, có thể là vì mục đích thống nhất ngôn ngữ sẽ cho phép "chuỗi" các cuộc gọi đến các chức năng như trong ví dụ của bạn. (Ít nhất là C++ có lẽ, vì nó cho phép loại đồng nhất này trong các câu lệnh return).

Tuy nhiên, trong ngôn ngữ C++ cũng như trong C, danh sách tham số có dạng (void) không được xử lý thống nhất với các dạng danh sách tham số khác. Thay vào đó, nó có một ý nghĩa đặc biệt. Nó có nghĩa là hàm có không có tham số nào cả ở số. (Tương đương với trống () trong C++).

Nói cách khác, hàm được khai báo có thông số (void) tham số số không. Bạn đang cung cấp một. Đây là những gì làm cho nó bất hợp pháp. Xét về ý nghĩa đặc biệt của (void) danh sách tham số trong C/C++, cho phép

foo(bar()); 

sẽ không khác nhiều so với cho phép

foo(bar(), bar()); 
foo(bar(), bar(), bar()); 

là tốt. Chất lượng, 2 và 3 là khác nhau nhiều so với 0, như 1 là.

2

Đừng bị lừa bởi ký hiệu. Thay vì khó chịu, C sử dụng nguyên mẫu f(void) để có nghĩa là "f hy vọng không có tham số" thay vì "f mong đợi một tham số duy nhất của loại void".Ký hiệu f() được giữ để có nghĩa là "số tham số mà f mong đợi không được biết, vì vậy bạn có thể gọi nó với bất kỳ số tham số nào bạn thích và chúc bạn may mắn". Trước khi ANSI Standard C (hay còn gọi là C89), không có thứ gì như một mẫu thử nghiệm chức năng, và bạn cần một công cụ như lint để bảo vệ bạn chống lại ngay cả các loại lỗi phổ biến nhất với các tham số, chẳng hạn như truyền sai số tham số hoặc truyền một tham số có loại không tương thích cực kỳ.

Vì lý do tại sao bạn không thể sử dụng giá trị của hàm trả về void làm giá trị hoặc lý do bạn không thể chuyển tham số đến hàm không mong đợi tham số, những hạn chế đó được thực hiện để bảo vệ bạn các loại lỗi phổ biến nhất với các tham số.

0

tôi sẽ bổ sung thêm một tuyên bố: void baz(int);

Bây giờ rõ ràng là nếu một cuộc tranh cãi với loại void bằng không có đối số, sau đó hai đối số, một trong số đó có kiểu trống sẽ tương đương với một đối số (như 0 = 1 * x < => 1 = 1 + 1 * x)

Vì vậy, rõ ràng điều này là hợp pháp: baz(1, bar());. Nhưng cũng (vì void là "không có gì") baz(bar(),1);.

Và chúng tôi có thể tiếp tục theo nghĩa này: baz(bar(), 1, bar());. Sau khi tất cả, "void là không có gì".

Hoặc là bạn cấm hoàn toàn, đưa ra các hạn chế tùy ý hoặc bạn sẽ chỉ cho phép các cấu trúc vô lý. Tôi đồng ý với lựa chọn cho độ phân giải đầu tiên

+0

Cũng sẽ dễ dàng để làm những gì tôi nói có thể và hợp pháp và không cho phép những gì bạn nói. Đừng quên các biểu thức trên là tất cả các dấu phẩy tách biệt, cho biết cả hai phải là một cái gì đó. Để giải thích bản thân mình tốt hơn: Nếu "void sẽ không là gì", thì ở trên sẽ bằng baz (1, "nothing"), điều này không hợp pháp vì "cái gì đó" được mong đợi. – George

Các vấn đề liên quan