声明
总结一下前几章讲的各种声明,并且进行混合使用。
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 int1
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)