C语言 分析声明的方法

声明是C语言中一个非常基础但重要的部分,无论是阅读他人的代码,还是排查编译报错,正确理解声明都会对我们有莫大的帮助。
有的人可能会说声明不是很简单吗?

小A说,看,我声明了一个整型变量:

int a;

小B说,瞧,我声明了一个函数:

int func(void);

我想大家理解上面的声明肯定是手拿把掐,轻而易举。

那么,下面几个声明呢?

int* arr[10];
int (*arr_ptr)[10];
int *func(int a);
int (*func_ptr)(int a);

以及这个呢?

int (*func_arr[5])(int a, int b);

如果你有点拿不准了,那就往下看吧,本文的目的就是给大家分享一下解析声明的方法,从而使得各位更好地理解 C 语言中的声明。

一、认识声明

首先让我们来看下声明的组成,一般来说,声明具体如下格式:

声明说明符 声明符;

声明说明符描述的是声明的数据项的性质,声明符描述的则是数据项的名字,并且描述了数据项性质的额外特点。

声明说明符有三大类:

  • 存储类型: autostaticexternregister
  • 类型限定符: constvolatile
  • 类型说明符: voidcharshortint

为了让大家便于理解,本文只讨论仅带类型说明符的声明,我想这是大家最熟悉的部分,存储类型与类型限定符我们以后再讨论。

接下来,让我们来认识一下声明符:声明符是由标识符、*[]()组成的。

  • 标识符:声明的变量或者函数的名字

    int a;
    

    这是最简单的声明符,其中a是标识符,由于没有其他符号,因此这个标识符a就是声明符。

  • *:如果在标识符前加一个*号,那么这个声明符表示指针

    int *p;
    
  • []:如果在标识符后加一个[],那么这个声明符表示数组

    int arr[10];
    
  • (): 如果在标识符后加一个(),那么这个声明符表示函数

    int add(int a, int b);
    

上面列出的几个声明符都很简单,但是我们在实际工作中遇到的声明符往往是标识符、*[]()的组合,也就是复杂声明符。接下来,让我们来看看如何分析复杂声明符。

二、声明的解析规则

有两条简单的规则可以帮助我们理解所有的声明,好的,划重点了:
第一条规则:由内而外

这条规则的含义就是,首先定位声明中的标识符,并由此开始解析

第二条规则:遇事不决找括号

当我们运用第一条规则找到标识符后,我们往往会发现标识符的左右两边有其他符号,这时候我们就会面临一个选择:向左走?向右走?

第二条规则为我们指明了方向,那就是找括号,即先()[],再*

举个栗子,让我们来分析如下声明:

int* arr[10];

根据第一条规则,我们首先找到标识符arr,然后从此处开始解析。

我们观察到在arr的左边是*,右边则是[10],那么arr是指针还是数组呢?

让我们运用第二条规则,先将arr[10]进行组合,这么一来**,arr的性质就确定了,它是一个数组**。

既然它是一个数组,那么就需要说明数组元素的类型和数量,数量我们已经知道了,10个,那么数组元素是什么类型呢?

根据第二条规则,接下来要解析*了,这说明数组元素的类型是指针,那么是什么类型的指针呢?int因此,我们知道了数组元素的类型是整型指针

综合起来,arr是一个包含10个元素的数组,每个元素的都是整型指针。

接着,我们来解析这条声明:

int *func(int a);

同样的,首先找到标识符,func,然后观察func的两边,发现左边是*,右边是(int a)

那么根据第二条规则,我们应该先将func(int a)结合,如此一来,func的性质就确定了,它是一个函数

既然是函数,那就要有参数和返回类型,根据(int a)我们可以知道,这个函数的接受一个整型参数。

对于返回类型,我们可以通过解析*得知,该函数的返回类型是一个指针,而指针的类型则是int,即整型指针。

综合起来,func是一个函数,它接收一个整型参数,返回类型是整型指针。

三、攻克复杂声明符

大家估计看出来了,第二条规则其实就是优先级的运用,因为()[]的优先级比*更高,所以我们先解析()[],再解析*

但是我们知道,()可以改变优先级,比如下面的声明:

int (*func_ptr)(int a, int b);

在上面的声明中,标识符func_ptr的左边是*,右边是(int a, int b),按照规则,应该先将func_ptr(int a, int b)结合,从而将func_ptr定性为函数。

但是,func_ptr*()包了起来,因此优先级被提高了,所以我们要先将func_ptr*号进行结合,因此func_ptr应该被定性为指针。

接着,我们要解析(int a, int b),从而可以确定func_ptr指向的是一个接受两个整型参数的函数,最后根据开头的int确定函数的返回值为整型。

综合起来就是,func_ptr是一个指向函数的指针,该函数接受两个整型参数的函数,返回类型是整型。

这种指针,我们一般叫它函数指针。

好了,有了以上经验,我们可以来解析本文的最终Boss了:

int (*func_arr[5])(int a, int b);

解析步骤如下:

  1. 找到标识符func_arr
  2. func_arr左边是*,右边是[5],因此先将func_arr[5]结合,从而将func_arr定性为数组,元素个数为5
  3. func_arr[5]的左边是*,右边是(int a, int b),但是func_arr[5]*被()包起来了,所以先解析*,从而确定数组的元素的类型是指针
  4. 接下来解析(int a, int b),可以确定指针指向的是一个接收两个整型参数的函数
  5. 最后根据开头的int确定函数的返回类型是整型

综合起来,func_arr是一个包含5个元素的数组,每个数组元素都是函数指针,指向的函数接受两个整型参数,返回类型是整型。

结语

希望通过本文的实例分析,可以帮助大家更好地理解和应用 C 语言中的各种声明语句。
若有错漏之处,欢迎大家交流指正~

最后,欢迎大家关注我的公众号《嵌入式3分钟》,一起学习嵌入式!
在这里插入图片描述

参考文献

[1] K.N.King, C语言程序设计:现代方法(第2版), 吕秀锋, 黄倩译,人民邮电出版社, 2010.

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TIME_LEAF

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值