浅谈C语言变量声明的解析
C语言本身提供了一种不甚明确的变量声明方式——基于使用的声明,如int *a,本质上是声明了*a的类型为int,所以得到了a的类型为指向int的指针。对于简单类型,这样声明并不会对代码产生多大的阅读障碍,而对于复杂的声明,比如标准库的signal函数签名,void (*signal( int sig, void (*handler) (int))) (int),这是什么?一眼看不出来吧,这是一个函数,接受两个参数,一个int,一个函数指针,而这个函数指针指向的函数接受一个int并返回void;返回一个函数指针,这个函数指针指向的函数接受一个int并返回void。尽管很多人都吵着说工程中谁写出来这样的代码就炒他鱿鱼,但人家标准库的确是写出了这样的代码的,你怎么办?
解析这样的复杂声明,我之前见过一种方法——右旋转法,方法是这样的:
- 从变量名开始,先右再左地,交替地一个一个向外看旁边的token,在纸上写下:“变量是”
- 若向右遇到左圆括号,在纸上写下:“函数,参数是”,并用同样的方法处理括号中每一个参数——在纸上写下:“返回”
- 若向右遇到方括号,在纸上写下:“数组,长度为{方括号的内容},元素类型为”
- 若向右遇到右圆括号,什么也不做
- 若向左遇到*,在纸上写下:“指针,指向”
- 若向左遇到任何类型,在纸上写下对应的类型名
我们用这种方法来处理下面的声明
void*(*(*fp1)(int))[10]
- 从fp1开始——fp1是
- 向右,遇到右括号,什么也不做
- 向左,遇到*——指针,指向
- 向右,遇到左圆括号——函数,参数是int,返回
- 向左,遇到*——指针,指向
- 向右,遇到左方括号——数组,长度为10,元素类型为
- 向左,遇到*——指针,指向
- 向右,已经到声明结尾,什么也不做
- 向左,遇到void——void
结果是:fp1是 指针,指向 函数,参数是int,返回指针,指向数组,长度为10,元素类型为 指针,指向 void
这种方法对于人来讲是比较合适的,因为他比较符合人脑的处理方式,但是也有一点缺点,如果函数的形参也写了名字,不是很熟练的小白,就不容易找到正确的起始位置,造成处理的混乱。
对于机器处理,这种从中间到两边的方法就不是很合适了,因为机器并不能直接在一个token序列中直接找到处理的起始位置,他只能从左到右进行扫描,我昨晚灵机一动想到一个算法,今天进行了试验,效果良好,没有对比一些比如cdecl.org那样的开源实现,我这个算法只是一个demo,并不完整支持C声明的处理,地址在这里。
算法从左到右扫描,本质上是递归下降,基本过程是这样的,为了方便说明,递归函数名为parse:
- parse开始
- if遇到类型,保存进变量a,递归parse,输出a
- elif遇到*,递归parse,输出"pointer to"
- elif遇到左圆括号,递归parse,并检查括号匹配
- elif遇到标识符,输出"{标识符} is"
- 控制流继续
- if遇到左方括号,输出"array with length {长度} of",并检查括号匹配
- elif遇到左圆括号,输出"function accepting",循环地递归parse,吃掉后面的逗号,直到遇到右圆括号,输出"returning"
- 返回
递归的意义是什么?每一个parse函数的意义都是:“我处理的这段东西的类型是——”,破折号后面的东西右这一层函数退出后上一层函数来补完,所以回去看上面的算法,遇到一个类型的时候,我就明白我下面一层处理的这段东西的类型是int,所以我递归调用parse,并输出int。
再从循环不变式的角度看parse的递归,parse的出口只有一个,那就是遇到的第一个if,不管是什么样的函数声明,最后都是以一个变量结尾的,而这里也是唯一一个把话说全了的分支——其他的分支都是输出类似于“xxx是”,“xxx返回”这样的没说完的话的,所以parse保证上一层的话都没有说完——从不是第一个if的分支退出,由这一层把话补全,这算某种意义上的循环不变式吧。
最后我把上面的声明拆成不同层数来表现一下parse的过程
void
* [10]
( )
* (int)
( )
*
fp1
浅谈C语言变量声明的解析的更多相关文章
- 浅谈C语言中的强符号、弱符号、强引用和弱引用
摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...
- 浅谈Java语言环境搭建-JDK8
title: 浅谈Java语言环境搭建-JDK8 blog: CSDN data: Java学习路线及视频 1.What's the JDK,JRE JDK(Java Development Kit ...
- C语言变量声明内存分配
转载: C语言变量声明内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...
- 浅谈C语言中断处理机制
一.中断机制 1.实现中断响应和中断返回 当CPU收到中断请求后,能根据具体情况决定是否响应中断,如果CPU没有更急.更重要的工作,则在执行完当前指令后响应这一中断请求.CPU中断响应过程如下:首先, ...
- 浅谈c语言结构体
对于很多非计算机专业来说,c语言课程基本上指针都不怎么讲,更别说后面的结构体了.这造成很多学生对结构体的不熟悉.这里我就浅谈一下我对结构体的认识. 结构体,就是我们自己定义出一种新的类型,定义好之后, ...
- C语言变量声明问题——变量定义一定要放在所有执行语句/语句块的最前面吗?
报错信息:error C2065: 'salary' : undeclared identifier #include <stdio.h> void main(){ printf(&quo ...
- 浅谈C# 匿名变量
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...
- C语言变量声明加冒号的用法
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C语言又提供了一种数据结构 ...
- 浅谈JS的变量提升
JS的解析机制,是JS的又一大重点知识点,在面试题中更经常出现,今天就来唠唠他们的原理.首先呢,我们在我们伟大的浏览器中,有个叫做JS解析器的东西,它专门用来读取JS,执行JS.一般情况是存在作用域就 ...
随机推荐
- java中与数据库的连接
package unitl01; import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet; ...
- Python-Day3知识点——深浅拷贝、函数基本定义、内置函数
一.深浅拷贝 import copy #浅拷贝 n1={'k1':'wu','k2':123,'k3':['carl',852]} n2=n1 n3=copy.copy(n1) print(id(n1 ...
- Unity3d游戏场景优化杂谈(2)
动态实时灯光相比静态灯光,非常耗费资源.所以除了能动的角色和物体(比如可以被打的到处乱飞的油桶)静态的地形和建筑,通通使用Lightmap. 强大的Unity内置了一个强大的光照图烘焙工具Beast, ...
- devexpress xaf 开发中遇到的问题.
devexpress xaf 开发中遇到的问题很多久了就忘记了.每天都把开发内容记录下来,方便大家,方便自己
- Python 程序员经常犯的 10 个错误
关于PythonPython是一种解释性.面向对象并具有动态语义的高级程序语言.它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得... 关于Python Python是一种解释性.面向对 ...
- matlab小段代码学习
matlab读hdf文件到txt filename='E:\data\H1BDLD10110607231863921.L2B.HDF'; h=hdftool(filename); Latitude = ...
- 0-Spark高级数据分析-读书笔记
学完了<Spark快速大数据分析>,对Spark有了一些了解,计划更近一步,开始学习<Spark高级数据分析>.这本书是用Scala写的,在学习的过程中想把其中的代码转换成Ja ...
- Emgu学习手册
作为opencv的c#封装库.emgu可以满足基本的图像处理功能,经过测试,效果还可以,主要用于windows窗体应用程序的开发,或者wpf,你可以用来做ocr,也可以用来做人脸识别或者可以用来做定位 ...
- UICollectionViewCell选中高亮状态和UIButton的高亮状态和选中状态
UICollectionViewCell选中高亮状态 //设置点击高亮和非高亮效果! - (BOOL)collectionView:(UICollectionView *)collectionView ...
- Advanced SystemCare 系统优化软件
这是一款国外非常流行的系统优化软件,功能很全面,而且中文版用起来也没有语言障碍. Pro版: C0184-8F31F-4B337-296F7 8DE4A-352D9-B4531-D60F7 5B91B ...