复杂声明的两件武器:右左法则(right-left rule)+ typedef 拆碎。
声明里的三个符号按优先级处理:
()(函数)、[](数组)——优先级最高;*(指针)——其次;() 用来改变结合顺序。所以 int *f(int) 是「f 是函数,返回 int*」,而 int (*f)(int) 是「f 是指针,指向函数」。
从一个声明里读出类型,按「从名字出发,先右后左,遇括号拐弯」的顺序:
[] 读「…的数组」、() 读「…的函数」;* 读「…的指针」、类型名读「指向…」;例:int *(*f[5])(char*)
f → f 是
[5] → 5 个元素的数组(向右)
* → 元素是「指针」(向左)
(char*) → 指向「接收 char* 的函数」(向右)
int * → 返回「int*」(向左)
结论:f 是「含 5 个指向 (char*)->int* 函数的指针的数组」
| 声明 | 读法 | 类型 |
|---|---|---|
int *p[5] | p 是含 5 个 int* 的数组 | 指针数组 |
int (*p)[5] | p 是指向 int[5] 的指针 | 数组指针 |
int *f(int) | f 是返回 int* 的函数 | 函数 |
int (*f)(int) | f 是指向 (int)->int 函数的指针 | 函数指针 |
int (*f[5])(int) | f 是含 5 个函数指针的数组 | 函数指针数组 |
int (*f(int))(char) | f 是函数,返回函数指针 | 返回函数指针的函数 |
任何复杂声明都能用 typedef 一层层拆,让每个中间类型都有名字:
// 原始:int *(*f[5])(char*)
typedef int *(*Handler)(char*); // Handler = 指向 (char*)->int* 函数的指针
Handler f[5]; // f 是含 5 个 Handler 的数组 —— 一眼看懂
标准库 signal 的声明是「复杂声明」的教科书案例:
void (*signal(int sig, void (*func)(int)))(int);
用 typedef 拆:
typedef void (*sighandler_t)(int); // 信号处理函数指针
sighandler_t signal(int sig, sighandler_t func); // 清晰
读法:signal 是函数,参数是 int 和「函数指针」,返回的也是「函数指针」——传一个处理函数进去,返回旧的处理函数。
std::function<int(char*)>、std::array<int,5>、auto 把复杂类型全藏起来了,auto f = &handler; 根本不用手写。从标识符出发,先右后左、遇括号拐弯;配合
typedef分层命名。