声明
总结一下前几章讲的各种声明,并且进行混合使用。
1. 声明的构成
- 属性说明符序列
- 说明符与限定符
- 声明符与初始化器
1.1 说明符与限定符
任意顺序的下列内容的空白符分隔列表:
- 类型说明符:
void
- 算术类型名
- 原子类型名
- 先前由
typedef
声明引入的名称 struct
、union
或enum
说明符typeof
说明符(C23 起)
- 零或一个存储类说明符:
typedef
、constexpr
、auto
、register
、static
、extern
、_Thread_local(thread_local)
- 零或多个类型限定符:
const
、volatile
、restrict
、_Atomic
- (只在声明函数时)零或多个函数说明符:
inline
、_Noreturn
- 零或多个对齐说明符:
_Alignas
以上是 任意顺序,可调换,比如:
c
const int n;
const int* const p = &n;
const const int* q = &n;
1
2
3
2
3
这里 const
是类型限定符,const int*
是类型说明符。
1.2 声明符与初始化器
- 定义:声明符的 逗号分隔列表(每个声明符提供附加类型信息和/或要声明的标识符)
- 声明符 可伴随初始化器
enum
、struct
和union
声明可忽略声明符,这种情况下它们仅引入枚举常量和/或标签。
1.3 属性说明符序列
可选的属性列表,应用到被声明的实体
1.4 声明符
声明符分为以下五种情况:
标识符 属性说明符序列
( 声明符 )
* 属性说明符序列
限定符 声明符第 1/3/4/5 种情况的声明符 [
static
限定符 表达式 ] 第 1/3/4/5 种情况的声明符 [ 限定符 * ]第 1/3/4/5 种情况的声明符 ( 形参或标识符 )
其中,第三种情况为指针声明符,第四种情况为数组声明符,第五种情况为函数声明符
其实就是把原来声明符的标识符替换成更复杂的东西,一层一层往下替换(很多类似的东西可以这么替换)
可以用英语方便地解释,遇到第三种就在前面加 pointer to,第四种加 array of,第五种加 function receives ... returns 比如 double (*f[])(int)
:double
2. 例子
2.1 int (*f(void))(void)
- 这个声明的 类型说明符 是
int
,声明符(*f(void))(void)
为第五种情况,是一个函数声明符,声明一个形参列表void
,返回int
的函数 - 上一条中所属声明符的 声明符 部分
(*f(void))
为第二种情况 - 上一条中所属声明符的 声明符 部分
*f(void)
为第三种情况,是一个指针声明符,声明一个指向一个形参列表void
,返回int
类型的函数的函数指针 - 上一条中所属声明符的 声明符 部分
f(void)
为第五种情况,是一个函数声明符,声明一个形参列表void
,返回“指向一个形参列表void
,返回int
类型的函数的函数指针”的函数 - 上一条中所属声明符的 声明符 部分为第一种情况,这个函数关联到标识符
f
2.2 int (*f(const void *))[3]
- 这个声明的类型说明符是
int
,声明符(*f(const void *))[3]
为第四种情况,是一个 数组声明符,声明一个长度为 3,类型为int
的数组 - 上一条中所属声明符的 声明符 部分
(*f(const void *))
为第二种情况 - 上一条中所属声明符的 声明符 部分
*f(const void *)
为第三种情况,是一个 指针声明符,声明一个指向一个长度为 3,类型为int
的数组的指针 - 上一条中所属声明符的 声明符 部分
f(const void *)
为第五种情况,是一个 函数声明符,声明一个接受一个const void*
类型形参,返回指向一个长度为 3,类型为int
的数组的指针的函数 - 上一条中所属声明符的 声明符 部分为第一种情况,这个函数关联到标识符
f
2.3 int(*(*r)(int(*(*)(int(*(*)())()))))[5]
写起来太难了,看注释吧
c
int(*(*r)(int(*(*)(int(*(*)())()))))[5] // array of int
(*(*r)(int(*(*)(int(*(*)())())))) // ()
*(*r)(int(*(*)(int(*(*)())()))) // pointer to array of int
(*r)(int(*(*)(int(*(*)())()))) // function returns pointer to array of int
(*r) // ()
*r // pointer to function returns pointer to array of int
(int(*(*)(int(*(*)())()))) // parameter list
int(*(*)(int(*(*)())())) // parameter 1
(*(*)(int(*(*)())())) // ()
*(*)(int(*(*)())()) // pointer to int
(*)(int(*(*)())()) // function returns pointer
(*) // ()
* // pointer to function returns pointer to int
(int(*(*)())()) // parameter list
int(*(*)())() // parameter 1
(*(*)())() // function returns int
(*(*)()) // ()
*(*)() // pointer to function returns int
(*)() // function returns pointer to function returns int
(*) // ()
* // pointer to function returns pointer to function returns int
// a pointer to function |- receives a parameter: pointer to function |- receives a parameter: pointer to function |- receives nothing(or unknown before C23)
// | | |- returns pointer to function |- reveives nothing(or unknown before C23)
// | | |- returns int
// | |- returns pointer to int
// |- returns pointer to array of int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3. typedef
声明
把标识符声明成类型别名,避免类型名过长
typedef
处于存储类说明符的位置,其余和正常声明无区别例子:
cauto char char1, *char_p1, (*f)(void); typedef char my_char_t, *my_char_p, (*fp)(void); fp fp2;
1
2
3auto
是存储类说明符,char1
具有char
类型,char_p1
具有char*
类型,fp1
具有char (*)(void)
类型typedef
放在上一句中auto
的位置:my_char_t
是char
的别名,my_char_p
是char*
的别名,fp
是char (*)(void)
的别名- 第三行相当于
char (*fp2)(void)