2013-10-27 17 views
8

tôi có các chức năng này hai thử nghiệm:Tại sao cả hai con trỏ hàm này đều hợp pháp trong C/C++?

int apply_a(int (*fun)(int, int), int m, int n) { 
    return (*fun)(m,n); 
} 

int apply_b(int (*fun)(int, int), int m, int n) { 
    return fun(m,n); 
} 

chúng xuất hiện trở lại một cái gì đó khác nhau, vậy tại sao cả trong số họ mang lại kết quả giống nhau không?

int add(int a, int b) {return a + b;} 

int res_a = apply_a(add, 2, 3); // returns 5 
int res_b = apply_b(add, 2, 3); // returns 5 

Tôi đã giả định rằng một trong số họ sẽ trả về địa chỉ con trỏ hoặc chính con trỏ; thay vì giá trị được lưu trữ trên con trỏ ...

Vậy tại sao lại thực hiện điều này?

+2

Bởi vì một trong hai cú pháp (có hoặc không có dấu hoa thị) là hợp lệ để gọi một chức năng thông qua một con trỏ. Trường hợp thứ hai là một cuộc gọi (bạn có thể biết bằng các dấu ngoặc đơn và các tham số đã truyền). – StoryTeller

+10

Không tốt. Bạn nên sử dụng '(*** fun) (m, n)' để đủ điều kiện làm lập trình viên ba sao. –

Trả lời

7

Vì C++ cung cấp đường cú pháp khi xử lý địa chỉ của các hàm không phải thành viên và sử dụng con trỏ cho chúng.

Người ta có thể có được địa chỉ của chức năng như:

int someFunc(int); 

với một trong hai:

int (* someFuncPtr)(int) = someFunc; 

hay:

int (* someFuncPtr)(int) = &someFunc; 

Ngoài ra còn có đường cú pháp cho việc sử dụng con trỏ như vậy, một trong hai cuộc gọi chức năng chỉ đến với:

(*someFuncPtr)(5); 

hoặc với cú pháp đơn giản:

someFuncPtr(5); 
+0

Hãy nhớ rằng điều tương tự cũng áp dụng cho phương pháp lớp tĩnh (ít nhất là trên Visual C++ 2012, nơi tôi đã kiểm tra;)) – altariste

+0

điều này cũng áp dụng trong C? hoặc là quy tắc đường chỉ dành cho C++? –

+0

C++ giới thiệu một ký pháp khác cho kiểu "hàm": 'int (int)' có thể chuyển thành 'int (*) (int)'. 'someFunc' có kiểu' int (int) 'trong khi' & someFunc' có kiểu 'int (*) (int)'. –

0

Trong C và C++ tên của chức năng cũng là những gợi ý để các mã chức năng. Như bất kỳ con trỏ nào, bạn có thể dereference chúng bằng cách sử dụng *, trong trường hợp con trỏ hàm có nghĩa là gọi hàm khi ngoài dereferencing bạn sử dụng cũng paranthesis sau chúng, như trong trường hợp apply_a của bạn. Nhưng cũng yêu cầu hợp lệ của hàm C và C++ là gọi chúng đơn giản bằng tên của chúng, đó là trường hợp apply_b.

+0

Nó không phải là tên. ** Bất kỳ biểu thức ** nào là một hàm, không chỉ là một tên hàm, sẽ được chuyển đổi thành một con trỏ trỏ đến hàm. –

1

Đó là vì bạn không trả lại địa chỉ bộ nhớ của các giá trị này. Gọi một hàm có con trỏ không thay đổi giá trị của nó, nó vẫn gọi hàm. Những gì bạn có thể làm là trả lại một giá trị cho một biến và sau đó nhận được đó là địa chỉ bộ nhớ như:

int result = fun(m,n); 
cout << "the result " << result << " pointing at " << &result << endl; 
6

(*fun)(m,n) cũng giống như fun(m,n) do quy tắc trong C và C++ chuyển đổi chức năng để trỏ đến các chức năng.

Trong C 2011, quy tắc là khoản 6.3.2.1 4: “A hàm thiết kế là một biểu thức có loại chức năng. Trừ khi nó là toán hạng của toán tử sizeof, các _Alignof hành, hoặc unary & điều hành, một vấn thiết kế chức năng với kiểu “chức năng trở loại” được chuyển thành một biểu thức có kiểu “con trỏ đến chức năng trả lại loại ”. Trong C++, quy tắc là điều khoản 4.3.

Lưu ý rằng một chỉ định chức năng không chỉ đơn thuần là một số nhận dạng đặt tên cho hàm.Nó có thể là một định danh, hoặc nó có thể là một biểu thức khác. Ví dụ: nếu foo là tên của một hàm, nó sẽ tự động được chuyển đổi thành con trỏ thành hàm bằng cách ở trên. Sau đó, kể từ foo là một con trỏ đến hàm, *foo là hàm. Điều này có nghĩa bạn có thể viết:

(*fun)(m,n) 

Kết quả là fun được tự động chuyển đổi sang một con trỏ, sau đó * đánh giá với chức năng, sau đó *fun được chuyển đổi trở lại một con trỏ, sau đó hàm được gọi. Bạn có thể tiếp tục điều này và viết:

(**************fun)(m,n) 

Điều này tương tự như fun(m,n). Mỗi * tạo lại hàm, nhưng trình biên dịch sẽ tự động chuyển đổi nó trở lại một con trỏ. Bạn có thể tiếp tục trận chiến này mãi mãi, nhưng trình biên dịch sẽ luôn thắng.

Trong thực tế, tất cả những có tác dụng tương tự:

(&fun)(m,n) 
(fun)(m,n) 
(*fun)(m,n) 
Các vấn đề liên quan