2010-11-08 9 views
12

Ngày nay, tôi đã được đọc APUE.and tôi tìm thấy các chức năng được xác định như sau:Làm thế nào để hiểu được điều này xác định

void (*signal(int signo, void (*func)(int)))(int); 

tôi đã nhầm lẫn, tôi biết tín hiệu là con trỏ đến một chức năng và cuối cùng (int) là thông số của anh ấy. tôi không biết cái gì (int signo, void (* func) (int)).

+1

Nhận 'cdecl'. Nó sẽ cho bạn biết tất cả những điều này. Tôi hỏi: 'giải thích void (* tín hiệu (int, void (*) (int))) (int);' và nó trả lời: 'khai báo tín hiệu như hàm (int, pointer to function (int) return void) trả về con trỏ đến function (int) trả về void' –

+0

thử http://cdecl.org/ –

Trả lời

23

Thủ tục chung : tìm số nhận dạng ngoài cùng bên trái và làm việc theo cách của bạn. Không có nhóm rõ ràng với dấu ngoặc đơn, các toán tử hậu tố như ()[] ràng buộc trước các toán tử đơn nhất như *; do đó, sau đây là tất cả sự thật:

T *x[N]    -- x is an N-element array of pointer to T 
T (*x)[N]   -- x is a pointer to an N-element array of T 
T *f()    -- f is a function returning a pointer to T 
T (*f)()   -- f is a pointer to a function returning T 

Áp dụng những quy tắc để việc kê khai, nó phá vỡ xuống như

 signal          -- signal 
     signal(       )  -- is a function 
     signal( signo,     )  -- with a parameter named signo 
     signal(int signo,     )  -- of type int 
     signal(int signo,  func  )  -- and a parameter named func 
     signal(int signo,  *func  )  -- of type pointer 
     signal(int signo,  (*func)( ))  -- to a function 
     signal(int signo,  (*func)(int))  -- taking an int parameter 
     signal(int signo, void (*func)(int))  -- and returning void 
     *signal(int signo, void (*func)(int))  -- returning a pointer 
    (*signal(int signo, void (*func)(int)))( ) -- to a function 
    (*signal(int signo, void (*func)(int)))(int) -- taking an int parameter 
void (*signal(int signo, void (*func)(int)))(int); -- and returning void 

Nói tóm lại, signal trả về một con trỏ tới một hàm trả về void. signal lấy hai tham số: một số nguyên và một con trỏ tới hàm khác trả về void.

Bạn có thể sử dụng typedef để giúp dễ đọc hơn (và trang hướng dẫn cho signal trên Ubuntu Linux thực hiện điều đó); tuy nhiên, tôi nghĩ rằng nó có giá trị để hiển thị phiên bản không được đánh máy để chứng minh chính xác cú pháp hoạt động như thế nào. Các cơ sở typedef là tuyệt vời, nhưng bạn thực sự cần phải hiểu làm thế nào các loại cơ bản làm việc để sử dụng nó một cách hiệu quả.

Chức năng signal thiết lập bộ xử lý tín hiệu; đối số thứ hai là hàm sẽ được thực thi nếu nhận được tín hiệu. Một con trỏ tới trình xử lý tín hiệu hiện tại (nếu có) được trả về.

Ví dụ, nếu bạn muốn chương trình của bạn để xử lý tín hiệu ngắt (chẳng hạn như từ Ctrl-C):

static int g_interruptFlag = 0; 

void interruptHandler(int sig) 
{ 
    g_interruptFlag = 1; 
} 

int main(void) 
{ 
    ... 
    /** 
    * Install the interrupt handler, saving the previous interrupt handler 
    */ 
    void (*oldInterruptHandler)(int) = signal(SIGINT, interruptHandler); 

    while (!g_interruptFlag) 
    { 
    // do something interesting until someone hits Ctrl-C 
    } 

    /** 
    * Restore the previous interrupt handler (not necessary for this particular 
    * example, but there may be cases where you want to swap out signal handlers 
    * after handling a specific condition) 
    */ 
    signal(SIGINT, oldInterruptHandler); 
    return 0; 
} 

EDIT tôi mở rộng mã ví dụ cho signal để cái gì đó là hy vọng minh họa hơn.

+1

+1 cho một câu trả lời tuyệt vời! – Shrayas

16
void (*signal(int signo, void (*func)(int)))(int); 

Tín hiệu là hàm lấy int và con trỏ hàm tham gia int và trả về khoảng trống và trả về một con trỏ hàm lấy int và trả về khoảng trống. Đó là,

typedef void(*funcPtr)(int) 

sau đó chúng tôi có

funcPtr signal(int signo, funcPtr func); //equivalent to the above 

Cú pháp là thực sự kỳ lạ, và điều đó tốt hơn được thực hiện với một typedef. Ví dụ, nếu bạn muốn khai báo một chức năng mà phải mất một int và trả về một con trỏ tới một hàm dùng char và gửi lại đôi sẽ

double (*f(int))(char); 

Edit: sau một comment mà đọc "Wooooooow", tôi đang cung cấp một ví dụ khác là "woooow" :)

Hãy khai báo một hàm mất
1. một con trỏ tới mảng của 5 con trỏ tới hàm hoạt động của từng con trỏ và trả về gấp đôi.
2. một con trỏ đến mảng của 3 ponters mảng 4 ints
và trả về một con trỏ đến hàm lấy một con trỏ đến hàm lấy int và trả về một con trỏ tới hàm lấy float và trả về void và trả về int không dấu.

Giải pháp typedef sẽ là:

typedef double (*f1ptr) (float); 
typedef f1ptr (*arr1ptr)[5]; 
typedef int (*arr2ptr)[4]; 
typedef arr2ptr (*arr3ptr)[3]; 
typedef void(*f2Ptr)(float); 
typedef f2ptr (*f3ptr)(int); 
typedef unsigned int (*f4ptr) (f3ptr); 
f4ptr TheFunction(arr1ptr arg1, arr3ptr arg2); 

Bây giờ, phần hài hước :) Nếu không có typedefs này sẽ:

unsigned int (*TheFunction(double (*(*)[5])(float), int(*(*)[3])[4]))(void(*(*)(int))(float)) 

thần của tôi, sao tôi chỉ cần viết đó? :)

+2

Wooooooooooooow – valdo

+0

@valdo: xem chỉnh sửa của tôi cho một wooooow tệ hơn :) –

+0

Hài hước? Phiên bản không phải là typedef'd là * hoàn toàn * trong suốt. –

12

Nguyên tắc chiều kim đồng hồ Spiral sẽ giúp: http://c-faq.com/decl/spiral.anderson.html

Có ba bước đơn giản để làm theo:

Bắt đầu với những yếu tố không rõ, di chuyển theo hướng xoắn ốc/chiều kim đồng hồ; khi ecountering các yếu tố sau thay thế chúng với những điều khoản tiếng Anh tương ứng:

kích thước

[X] hoặc [] => Array X của ... hoặc mảng kích thước không xác định của ...

(type1, type2) = > function đi type1 và type2 trở về ...

  • => con trỏ (s) để ...

Giữ làm điều này trong một vòng xoáy/chiều kim đồng hồ cho đến khi tất cả các thẻ đã được bảo hiểm. Luôn giải quyết mọi thứ trong dấu ngoặc đơn trước!

Xem "Ví dụ 3: Các 'Cuối cùng'", mà là khá nhiều chính xác những gì bạn đang yêu cầu:

"tín hiệu là một chức năng thông qua một int và một con trỏ tới một hàm đi qua một int trở về không có gì (void) trả về một con trỏ tới một hàm đi qua một int trở về không có gì (void)"

+0

Đây là một nguồn tài nguyên tuyệt vời. Cảm ơn ! – Shrayas

0

Install cdecl cho phân phối của bạn (nếu có) hoặc đi here

nếu không, tôi tin rằng câu trả lời Armen Tsirunyan là đúng.

3

Trong trường hợp bạn không có quyền truy cập vào cdecl ngay bây giờ, đây là sản phẩm cdecl:

$ cdecl 
cdecl> explain void (*signal(int , void (*)(int)))(int); 
declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void