2012-02-17 28 views
22
#include<stdio.h> 
#include<stdlib.h> 

int fun1() 
{ 
    printf("I am fun1."); 
    return 0; 
} 

int fun2(int fun()) 
{ 
    fun(); 
    return 0; 
} 

int main() 
{ 
    fun2(fun1); 
    return 0; 
} 

Chương trình trên có thể chạy. Theo như tôi quan tâm, tôi có thể hiểu được int fun2(int (*fun)()), nhưng tôi không biết cách hoạt động của int fun2(int fun()). Cảm ơn bạn.Giới thiệu về con trỏ đến hàm trong khai báo hàm

+3

Hợp lệ trong C, C99 Nghiêm ngặt, C++ 03 và C++ 11. Và tôi ngạc nhiên. –

Trả lời

32

Khi bạn viết int fun2(int fun()), tham số int fun() chuyển đổi thành int (*fun)(), nó trở nên chính xác tương đương như sau:

int fun2(int (*fun)()); 

Chuyển đổi famiiar hơn xảy ra trong trường hợp của mảng khi bạn khai báo nó như là tham số chức năng. Ví dụ, nếu bạn đã này:

int f(int a[100]); 

Thậm chí ở đây các loại tham số chuyển đổi thành int*, và nó trở thành này:

int f(int *a); 

Lý do tại sao loại chức năng và kiểu mảng chuyển đổi thành chức năng con trỏ loại và kiểu con trỏ, tương ứng, là vì tiêu chuẩn không cho phép hàm và mảng được chuyển đến hàm, bạn cũng không thể trả về hàm và mảng từ hàm. Trong cả hai trường hợp, chúng phân rã thành phiên bản con trỏ của chúng.

Tiêu chuẩn C++ 03 nói trong §13.1/3 (và nó là giống trong C++ 11 cũng),

tờ khai Parameter mà chỉ khác nhau ở một trong đó là một loại chức năng và người kia là con trỏ tới cùng một loại hàm là tương đương. Tức là, loại chức năng được điều chỉnh để trở thành con trỏ thành kiểu hàm (8.3.5).

Và một cuộc thảo luận thú vị hơn là ở đây:

+2

+1 Để lưu ý sự giống nhau về mảng. – asaelr

+4

Câu trả lời hay. Ngoài ra, tôi không có ý tưởng rằng điều này đã làm việc! –

+0

cảm ơn bạn. tôi đã bị bối rối trong một thời gian dài. – dragonfly

6

int fun2(int (*fun)())int fun2(int fun()) hoàn toàn giống nhau. Khi bạn khai báo một đối số hàm từ một kiểu hàm, trình biên dịch sử dụng nó như thể nó là một con trỏ trỏ đến cùng một kiểu hàm.

-3

Nhìn để nó ở một mức độ thấp hơn (và trong một kiến ​​trúc x86-based):

int fun2(int fun()) 

int vui vẻ() 's địa chỉ được đẩy vào ngăn xếp và truyền cho fun2() chức năng.

int fun2(int (*fun)()) 

int vui vẻ() 's con trỏ địa chỉ được đẩy vào ngăn xếp và truyền cho fun2 function().

Kết quả là như nhau, ngoại trừ kết quả thứ hai, bạn chuyển địa chỉ của niềm vui() theo tham chiếu và trong trường hợp đầu tiên bạn chuyển nó theo giá trị.

+0

Sự khác nhau giữa địa chỉ của hàm và địa chỉ con trỏ của hàm là gì? Hoặc, bạn có ý gì bởi cụm từ "địa chỉ con trỏ"? –

+0

Bằng địa chỉ con trỏ, ý tôi là *** p *. Đó là, địa chỉ của con trỏ đến địa chỉ của hàm. – m0skit0

+0

Bạn có ý gì bởi _ ** p_? Điều đó có vẻ như một cái gì đó có thể bị hủy bỏ hai lần bị hủy đăng ký hai lần? Địa chỉ của một con trỏ tới một hàm sẽ là một cái gì đó như: 'int (* fnptr)(); int (** p)() = &fnptr; 'nhưng không có gì giống như xuất hiện trong câu hỏi? –

3

Hai định nghĩa chức năng tương đương trong C:

int fun2(int fun()) { ... } 

int fun2(int (*fun)()) { ... } 

Trong hàm đầu tiên, tham số được điều chỉnh thành con trỏ hàm. Xem C Đoạn tiêu chuẩn:

(C99, 6.7.5.3p8) "Việc khai báo tham số dưới dạng '' trả về hàm '' phải được điều chỉnh thành '' con trỏ tới hàm trả về '', như trong 6.3 .2.1. "

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