让我们从一般的声明语法开始(我将使用 C 术语,尽管 C++ 大体相似)。在 C 和 C++ 中,声明包含一个或多个 声明说明符 的序列,后跟零个或多个 声明符 的逗号分隔列表。
声明说明符包括类型说明符(int、double、char、unsigned 等)、类型限定符(const、volatile 等)、存储类说明符(@987654327 @、register、typedef 等)、struct 和 union 说明符,以及其他一些我们不会在这里讨论的内容。
声明符包括被声明事物的名称,以及有关该事物的指针性、数组性或函数性的信息(在 C++ 中,您还具有引用性)。
当你声明一个函数时,比如
void foo( int, double );
void是声明说明符(类型说明符),foo( int, double )是声明符。 foo 的类型完全由声明说明符和声明符的组合指定:
foo -- foo
foo( ) -- is a function taking
foo( ) -- unnamed parameter
foo( int ) -- is an int
foo( int, ) -- unnamed parameter
foo( int, double ) -- is a double
void foo( int, double ) -- returning void
用简单的英语来说,foo 的类型是“函数接受 int 和 double 参数并返回 void。”
你也可以声明指向函数的指针:
fptr -- fptr
(*fptr) -- is a pointer to
(*fptr)( ) -- function taking
(*fptr)( ) -- unnamed parameter
(*fptr)( int ) -- is an int
(*fptr)( int, ) -- unnamed parameter
(*fptr)( int, double ) -- is a double
void (*fptr)( int, double ) -- returning void
同样,唯一的声明说明符是void,声明符是(*fptr)( int, double )。
出于语法目的,typedef 与存储类说明符(static、auto、register)分组,但它的行为与其他存储类说明符不同 - 不会影响存储或可见性在声明的事物中,它使声明符中的标识符成为类型的别名。如果我们在上述声明的前面加上typedef:
typedef void (*fptr)( int, double );
然后它读作
fptr -- fptr
typedef fptr -- IS AN ALIAS FOR THE TYPE
typedef (*fptr) -- pointer to
typedef (*fptr)( ) -- function taking
typedef (*fptr)( ) -- unnamed parameter
typedef (*fptr)( int ) -- is an int
typedef (*fptr)( int, ) -- unnamed parameter
typedef (*fptr)( int, double ) -- is a double
typedef void (*fptr)( int, double ) -- returning void
IOW,fptr 是类型“指向带有int 和double 参数并返回void 的函数的指针”的别名(typedef 名称),您可以使用它来声明指针对象那种类型的:
fptr fp1, fp2;
你可以用其他指针类型做同样的事情1:
typedef int *intp; // intp is an alias for the type "pointer to int";
typedef double (*arr)[10]; // arr is an alias for the type "pointer to 10-element array of double"
声明器可以变得相当复杂。您可以拥有指向函数的指针:
T (*ptr)();
指向数组的指针:
T (*ptr)[N];
函数指针数组:
T (*ptr[N])();
函数返回指向数组的指针:
T (*foo())[N];
指向函数的指针数组返回指向数组的指针:
T (*(*arr[N])())[M];
不断地不断地,在它们前面贴上typedef 将起作用:
typedef T (*(*arr[N])())[M];
表示arr 是“指向函数的N 元素数组指针返回指向T 的M 元素数组的指针”类型的别名。
- 通常,您不希望将指向标量类型的指针隐藏在 typedef 后面,除非您可以保证使用该类型的程序员永远不必知道该类型的底层指针性(即,永远不必用
* 显式取消引用它,或者尝试用%p 或类似的东西打印它的值)。