2012-02-20 40 views
9

Tôi nghĩ rằng tôi có thể bị bệnh "lập trình ngẫu nhiên" sợ hãi, ít nhất là khi nói đến typedef và các con trỏ hàm. Vì vậy, tôi đã thử nghiệm với tất cả các loại kết hợp liên quan đến việc này để phân tích các kết quả dựa trên tất cả các đầu ra tôi nhận được.Cách typedef hoạt động với các con trỏ hàm

Nhưng khi tôi tiếp tục thử các kết hợp khác nhau, thay vì phân tích kết quả, tôi hiện chỉ bị mất trong quá trình.

Tôi hy vọng các bạn sẽ giúp tôi tìm ra mớ hỗn độn này.

mã đầu tiên ví dụ

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = &do_something; 
pr(); // Hello World 

mã thứ hai dụ

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = do_something; 
pr(); // Hello World 

Làm thế nào để cả hai mã trên ví dụ làm việc, nó như thể '&' không ảnh hưởng đến tên hàm

mã thứ ba ví dụ

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print pr; 
pr = do_something; // compile error 
pr = &do_something; // compile error 
pr(); 

Tôi đã hy vọng một trong những bài tập ở trên để làm việc ở đây nhưng chết tiệt! Tôi thực sự không hiểu con trỏ hàm (và có thể typedef quá).

+1

Điều này có thể giúp http://stackoverflow.com/questions/4298654/operator-optional-in-function-pointer-assignment –

+0

Umm ... Tôi nghĩ bạn nên tạo cho mình một 'Lập trình C chuyên nghiệp' nó khám phá biến của C xác định quy tắc. Tôi sẽ cố gắng để tìm nó trực tuyến cho bạn – shengy

+1

chỉ google lập trình C chuyên nghiệp, đầu tiên là cuốn sách. Tìm kiếm 'Cách khai báo được tạo thành' và tôi nghĩ bạn sẽ nhận được câu trả lời – shengy

Trả lời

18

Địa chỉ của tên hàm và tên hàm thuần đều có cùng ý nghĩa, vì vậy & không ảnh hưởng đến tên hàm.

Tương tự như vậy, khi sử dụng con trỏ hàm, nhiều dereferencing không phải là một vấn đề:

#include <stdio.h> 
typedef void print(void); 
static void dosomething(void) { printf("Hello World\n"); } 

int main(void) 
{ 
    print *f1 = dosomething; 
    print *f2 = &dosomething; 
    f2(); 
    (f1)(); 
    (*f1)(); 
    (**f2)(); 
    (***f1)(); 
    (****f2)(); 
    (*****f1)(); 
} 

Đó biên dịch sạch dưới:

gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \ 
    -Wold-style-definition -std=c99 xx.c -o xx 

tôi sẽ không cho rằng nhiều sao là phong cách tốt; không phải vậy. Nó là 'kỳ quặc, và (có, bạn có thể nói nó) nghịch đảo'.Một là đủ (và một ngôi sao chủ yếu dành cho những người như tôi đã học lập trình trong C trước khi tiêu chuẩn nói "không thể gọi một hàm qua con trỏ mà không sử dụng ký hiệu (*pointer_to_function)(arg1, arg2); bạn chỉ có thể viết pointer_to_function(arg1, arg2) nếu muốn"). Có, nó là lạ. Không, không có loại nào khác (hoặc loại của các loại) thể hiện hành vi tương tự, cảm ơn lòng tốt.

+1

Bây giờ là lạ và tôi có thể nói, ngược lại. Để thử và thực sự biên dịch. :) –

+4

+1, để làm cho nó rõ ràng, chức năng và chức năng con trỏ không giống nhau, nhưng trước đây có xu hướng tự động phân rã để sau này trong hầu hết các bối cảnh (mặc dù không phải tất cả). Trong biểu thức '** f2', con trỏ hàm bị bỏ qua và hàm kết quả ngay lập tức phân rã trở lại con trỏ, sau đó lại bị bỏ qua. – avakar

+2

Mảng có hành vi tương tự, mặc dù không giống nhau, "phân rã tự động". Đối với 'int x [10];', địa chỉ của 'x' và' & x' giống nhau. Nhưng kiểu của họ thì khác, và bạn không thể sử dụng tháp hình sao đẹp được hiển thị ở đây. – ugoren

3

Nó chỉ ra rằng, trong C/C++, cả hai funcname&funcname sẽ mang lại địa chỉ funcname và có thể được gán cho một biến con trỏ hàm. Đây thực sự chỉ là một sự kỳ quặc về cách cú pháp được thiết kế cho (các) ngôn ngữ.

7

Điều về con trỏ hàm là chúng hoạt động con trỏ! :-) Đây là cách bạn có được mẫu thứ ba của bạn để làm việc:

#include <stdio.h> 
typedef void (*print)(void); 
//   ^
void do_something (void) { printf("Hello World\n"); } 
int main (void) { 
    print pr; 
    pr = do_something; // &do_something would also work. 
    pr(); 
    return 0; 
} 

Về dù bạn sử dụng funcName hoặc &funcName, nó không quan trọng (trong C ít nhất). Mục 6.3.2.1 Lvalues, arrays and function designators tiểu bang:

Trình chỉ định hàm là biểu thức có loại chức năng. Ngoại trừ khi nó là toán hạng của toán tử sizeof hoặc toán tử & đơn nhất, một hàm thiết kế với kiểu "hàm trả về kiểu" được chuyển đổi thành một biểu thức có kiểu "pointer to function return type".

+0

điên rồ rằng phiếu bầu đầu tiên là một câu trả lời: -/ –

3

Giống như C, C++ có con trỏ đến hàm: void (*)() chẳng hạn là một con trỏ trỏ đến hàm không nhận đối số và trả về không có giá trị. Tuy nhiên, C++ cũng đã giới thiệu các tham chiếu đến các hàm void (&)() và có các chuyển đổi tiềm ẩn giữa hai hàm (mặc dù tôi không nhớ chính xác các quy tắc).

Do đó:

  • funcname là một tham chiếu đến hoạt
  • &funcname là một con trỏ đến hoạt

Lưu ý rằng lấy địa chỉ (hoặc một tham chiếu đến) một hàm bị quá tải đòi hỏi a static_cast đến loại chính xác (để giải quyết tình trạng quá tải).

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