Loại quy tắc "xoắn ốc" rơi ra khỏi các quy tắc ưu tiên sau:
T *a[] -- a is an array of pointer to T
T (*a)[] -- a is a pointer to an 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
Các toán tử []
gọi hàm và hàm con ()
có độ ưu tiên cao hơn unary *
, do đó *f()
được phân tích cú pháp *(f())
và *a[]
được phân tích cú pháp như *(a[])
.
Vì vậy, nếu bạn muốn một con trỏ tới một mảng hoặc một con trỏ tới một hàm, thì bạn cần phải nhóm một cách rõ ràng *
với mã định danh, như trong (*a)[]
hoặc (*f)()
.
Sau đó, bạn nhận ra rằng a
và f
có thể là các biểu thức phức tạp hơn chỉ là các định danh; trong T (*a)[N]
, a
có thể là một định danh đơn giản hoặc có thể là một hàm gọi như (*f())[N]
( a
-> f()
) hoặc nó có thể là một mảng như (*p[M])[N]
, ( a
-> p[M]
) hoặc nó có thể là một mảng các con trỏ tới các hàm như (*(*p[M])())[N]
( a
-> (*p[M])()
), Vân vân.
Sẽ thật tuyệt nếu toán tử gián tiếp *
là postfix thay vì unary, điều này sẽ làm cho các khai báo dễ đọc hơn từ trái sang phải ( void f[]*()*();
chắc chắn chảy tốt hơn void (*(*f[])())()
), nhưng thực tế không phải vậy.
Khi bạn gặp một khai báo lông như thế, hãy bắt đầu bằng cách tìm định danh ngoài cùng bên trái và áp dụng các quy tắc ưu tiên ở trên, áp dụng đệ quy chúng cho bất kỳ tham số chức năng nào:
f -- f
f[] -- is an array
*f[] -- of pointers ([] has higher precedence than *)
(*f[])() -- to functions
*(*f[])() -- returning pointers
(*(*f[])())() -- to functions
void (*(*f[])())(); -- returning void
Các signal
chức năng trong thư viện chuẩn có lẽ là mẫu kiểu cho các loại hình của sự điên rồ:
signal -- signal
signal( ) -- is a function with parameters
signal( sig, ) -- sig
signal(int sig, ) -- which is an int and
signal(int sig, func ) -- func
signal(int sig, *func ) -- which is a pointer
signal(int sig, (*func)(int)) -- to a function taking an int
signal(int sig, void (*func)(int)) -- returning void
*signal(int sig, void (*func)(int)) -- returning a pointer
(*signal(int sig, void (*func)(int)))(int) -- to a function taking an int
void (*signal(int sig, void (*func)(int)))(int); -- and returning void
Tại thời điểm này, hầu hết mọi người nói "sử dụng typedefs", đây chắc chắn là một lựa chọn:
typedef void outerfunc(void);
typedef outerfunc *innerfunc(void);
innerfunc *f[N];
Nhưng...
Làm thế nào bạn sẽ sử dụng f
trong một biểu thức? Bạn biết đó là một mảng các con trỏ, nhưng làm thế nào để bạn sử dụng nó để thực hiện đúng chức năng? Bạn phải đi qua các typedefs và giải đúng cú pháp. Ngược lại, phiên bản "trần trụi" khá đẹp mắt, nhưng nó cho bạn biết chính xác cách sử dụng f
trong một biểu thức (cụ thể là (*(*f[i])())();
, giả sử không có hàm nào có đối số).