2012-06-24 35 views
5

Xét mã này với 3 differents chức năng ngữ nghĩa cuộc gọi:gọi hàm với ngữ nghĩa khác nhau

void f(void){ 
    puts("OK"); 
} 

int main(void){ 
    f(); 
    (*f)(); 
    (&f)(); 

    return 0; 
} 

Đầu tiên là cách tiêu chuẩn để gọi f,

thứ hai là ngữ nghĩa cho dereferencing con trỏ hàm,

nhưng trong phần ba, tôi đang áp dụng toán tử & cho tên hàm và dường như hoạt động tốt.

Điều gì xảy ra trong trường hợp thứ hai và thứ ba xảy ra?

Cảm ơn.

+1

Con trỏ tới hàm bị hủy tham gia cuộc gọi ở phần thứ ba. –

+5

Để vui thử '(********** f)();' cũng như – Flexo

+0

Tôi hỏi trong trường hợp ai đó nên sử dụng lệnh gọi thứ hai và thứ ba ... –

Trả lời

8

Các cuộc gọi chức năng là luôn luôn được thực hiện thông qua các con trỏ hàm. Từ phần C99 6.5.2.2:

Biểu thức biểu thị hàm được gọi sẽ có con trỏ loại hoạt động.

Tuy nhiên, trong hầu hết các trường hợp, một loại hàm phân rã thành loại con trỏ hàm. Từ C99 phần 6.3.2.1:

Trừ khi nó là toán hạng của toán tử sizeof hoặc & hành unary, một vấn thiết kế chức năng với gõ "chức năng trở loại" được chuyển thành một biểu thức có nhập "pointer to function return type".

Vì vậy, ba cuộc gọi của bạn được đánh giá như sau:

(&f)(); 
(&(*(&f)))(); 
(&f)(); 

Tất cả đều hợp lệ. Nhưng rõ ràng, người đầu tiên (f()) là người sạch và dễ đọc nhất.

+0

tại sao không (& (& f)()) hợp lệ. Khi & f phân rã thành kiểu con trỏ chức năng? – Raulp

+0

@softy: '& f' là ** đã ** loại hàm con trỏ. Vì vậy, '&& f' là một kiểu con trỏ trỏ hàm. –

+6

@OliCharlesworth - Chỉ có '& f' là giá trị r, do đó, nó không thể là đối số của toán tử' & 'đơn nhất khác. – rodrigo

1

Trong trường hợp thứ hai bạn đang sử dụng một con trỏ hàm. Con trỏ hàm được sử dụng để ghi nhớ tham chiếu đến hàm và có thể gọi nó ở nơi khác trong cuộc gọi của bạn. Chúng thường được sử dụng để thực hiện các cuộc gọi lại. Vì vậy, nếu bạn lưu trữ một con trỏ đến một hàm, bạn nên sử dụng ký pháp đầu tiên.

Tôi nghĩ rằng thứ nhất và thứ ba là tương đương. Thực tế, nếu bạn khai báo một con trỏ hàm, bạn có thể khởi tạo nó theo cả hai cách sau:

void AFunction(); 
void (*funcPtr)() = NULL; 

funcPtr = AFunction; 
funcPtr = &AFunction; 
Các vấn đề liên quan