c语言复杂声明的解释

目标:分析一个将c语言复杂申明解释为英语的一个程序

首先介绍一种简单的读声明的方法,来源网络

1.右左法则

从标识符开始(或者最内层的结构,如果不存在标识符的话,通常出现于函数指针),首先向右看,直到遇到 ) 括号或者结束,看到什么就说出来;然后向左看,直到遇到 ( 括号或者回到行首,看到什么就说出来。跳出一层括号,重复上述过程:右看看,说出来;左看看,说出来。直到你说出变量的类型或者返回值(针对函数指针),也就表示你把声明都读完了。

2.例子

int *a[3];

从标示符a开始,向右看,a是一个包含三个元素的数组,向左看数组的每个元素是指针,向右看到结尾了,向左看,指针指向int。综合:a是一个三元数组,数组的每个元素是指针,指向int。

int (*a)[3];

从标示符a开始,向右看,遇到(,向左看,a是一个指针,向右看,指针指向一个包含三个元素的数组,向左看,数组类型为int。

int (*foo)();

从标示符foo开始,向右看,遇到),向左看,foo是一个指针,想左看,指针指向一个无参数的函数,向右看,函数返回类型位int。

int (*(*vtable)[])();

这个比较复杂,还是从标示符table开始,向右看,遇到),向左看,table是一个指针,指针指向一个数组,向左看,数组的元素是指针,向右看,指针指向一个无参数的函数,向右看,函数的返回类型为int。

实践完这些例子,基本就能明白右左法则。此法则能帮助我们快速的理解复杂声明,接下来将分析一个《c程序语言设计》中的一个复杂声明解释程序,但所用方法与此处的左右法则不同。

此程序是基于声明符语法编写,其语法简化形式:

dcl: 前面带有可选的direct-dcl

direct-dcl: name,(dcl),direct-dcl(),direct-dcl[ ]

简而言之,声明符dcl就是前面可能带有多个*的direct-dcl,direct-dcl可以是name,由一对圆括号括起来的dcl,后面跟有一对圆括号的direct-dcl,后面跟有用方括号括起来的direct-dcl。

代码

#include <stdio.h>
#include <string.h>
#include <ctype.h> #define MAXTOKEN 100 enum { NAME, PARENS, BRACKETS }; void dcl(void);
void dirdcl(void);
int gettoken(void);
int get_line(char s[], int lim);
int tokentype;
char token[MAXTOKEN];
char name[MAXTOKEN];
char datatype[MAXTOKEN];
char out[1000]; //衔接词 #define BUFSIZE 1024
char buf[BUFSIZE];
char line[BUFSIZE];
int bufp = 0;
int linep = 0; int getch(void){
if (bufp > 0 || (line[linep] !='\0'))
return (bufp > 0) ? buf[--bufp] : line[linep++];
else
return EOF;}
void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters ");
else
buf[bufp++] = c;
} int main(int argc, char* argv[])
{
get_line(line, BUFSIZE);
while (gettoken() != EOF) {
strcpy(datatype, token);
out[0] ='\0';
dcl();
if (tokentype !='\n')
printf("syntax error ");
printf("%s: %s %s ", name, out, datatype);
}
return 0;
} int gettoken(void)
{
int c;
char *p = token;
while ((c = getch()) == ' ' || c == '\t') //去除空格和换行符
;
if (c == '(') {
if ((c = getch()) == ')') {
strcpy(token, "()");
return tokentype = PARENS;
} else {
ungetch(c);
return tokentype = '(';
}
}
else if (c == '[') {
for (*p++ = c; (*p++ = getch()) != ']';)
;
*p ='\0';
return tokentype = BRACKETS;
}
else if (isalpha(c)) {
for (*p++ = c; isalnum(c = getch());)
*p++ = c;
*p ='\0';
ungetch(c);
return tokentype = NAME;
}
else
return tokentype = c;
}
int get_line(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c !='\n')
s[i++]=c;
if (c == '\n')
s[i++]=c;
s[i]='\0';
return i;
}
void dcl(void)
{
int ns;
for (ns = 0; gettoken() == '*';)
ns++;
dirdcl();
while (ns-- > 0)
strcat(out, " pointer to");
} void dirdcl(void)
{
int type; if (tokentype == '(') {
dcl();
if (tokentype != ')')
printf("error: missing ) ");
}
else if (tokentype == NAME)
strcpy(name, token);
else
printf("error: expected name or (dcl) ");
while ((type = gettoken()) == PARENS || type == BRACKETS)
if (type == PARENS)
strcat(out, " function returning");
else {
strcat(out, " array");
strcat(out, token);
strcat(out, " of");
}
}

c语言复杂申明解释程序的更多相关文章

  1. C语言函数申明关键字inline

    内联inline是给编译器的优化提示,如果一个函数被编译成inline的话,那么就会把函数里面的代码直接插入到调用这个函数的地方,而不是用调用函数的形式.如果函数体代码很短的话,这样会比较有效率,因为 ...

  2. c/c++排坑(5) -- c语言中的申明

    C语言的申明总是令人头大,对于这块内容也一直让我头疼.希望通过这篇博客能够稍微梳理一下.材料和例子来源于<C专家编程> 一.C语言的申明的优先级规则 先来个例子,看看下面这行C代码到底是个 ...

  3. C语言中的声明解析规则——数组,指针与函数

    摘要:C语言的申明存在的最大问题是:你无法以一种人们所习惯的自然方式和从左向右阅读一个声明,在引入voliatile和const关键字以后,情况更加糟糕了.由于这些关键字只能出现在声明中,是的声明形式 ...

  4. 彻底搞定C语言指针(精华版)

    1.语言中变量的实质 要理解C指针,我认为一定要理解C中“变量”的存储实质, 所以我就从“变量”这个东西开始讲起吧! 先来理解理解内存空间吧!请看下图: 内存地址→ 6 7 8 9 10 11 12 ...

  5. go语言调度器源代码情景分析之三:内存

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第2小节. 内存是计算机系统的存储设备,其主要作用是协助CPU在执行程序时存储数据和指令. 内存由大量内存单元组成,内存单元大小为 ...

  6. 基于windows IIS的C语言CGI WEB服务器环境搭建

    网页编程对我来说特别亲切,因为我就是从html.ASP.PHP一步步接触编程的.自己的编程爱好也是从那里一点一点被满足.不过离开大学之后很久没有碰过WEB了,最近看到嵌入式中的涉及到的web服务器,了 ...

  7. Python - Tips

    01 - input与raw_input的区别 input() #可以直接输入数字,但输入字符的要用引号''或者双引号"" raw_input() #将所有的输入都直接当作一串字符 ...

  8. Unity3D着色器Shader编程入门(一)

    自学Unity3D也有大半年了,对Shader一直不敢入坑,最近看了些资料,以及通过自己的实践,对Shader还是有一点了解了,分享下仅作入门参考. 因Shader是对图像图像渲染的,学习前可以去了解 ...

  9. 彻底搞定 C/C++ 指针

    1.语言中变量的实质 要理解C指针,我认为一定要理解C中“变量”的存储实质, 所以我就从“变量”这个东西开始讲起吧! 先来理解理解内存空间吧!请看下图: 内存地址→ 6 7 8 9 10 11 12 ...

随机推荐

  1. K2 BPM_规范内部供应链流程,提高企业整体绩效_工作流流程管理

    方案背景 随着企业竞争的加剧.顾客需求的多样化以及市场变化的不确定因素增多,企业与企业间的竞争已经逐步转变为供应链与供应链间的竞争.企业只有在内部各业务流程有机统一的状态下,再与外部企业进行融合与协作 ...

  2. iOS 中 UIView 和 CALayer 的关系

    UIView 有一个名叫 layer ,类型为 CALayer 的对象属性,它们的行为很相似,主要区别在于:CALayer 继承自 NSObject ,不能够响应事件. 这是因为 UIView 除了负 ...

  3. 7层网络以及5种Linux IO模型以及相应IO基础

    一.七层网络模型 OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制定了OSI模型,该模型定义了不同计算机互联的标准,它是一个七层的. ...

  4. c# 输出参数-out

  5. 记录java+testng运行selenium(二)---定义元素类及浏览器

    一: 元素类 整体思路: 1. 根据状态可分可见和不可见两种 2. 同一个路径可以查找单个元素或多个元素 3. 获取元素text或者指定的value值 4. selenium对元素操作有两种,一是通过 ...

  6. Tensorflow&CNN:裂纹分类

    版权声明:本文为博主原创文章,转载 请注明出处:https://blog.csdn.net/sc2079/article/details/90478551 - 写在前面 本科毕业设计终于告一段落了.特 ...

  7. ES6 正则扩展

    一.新增 flags 属性 ES6 为正则表达式新增了flags属性,会返回正则表达式的修饰符. // ES5 的 source 属性 // 返回正则表达式的正文 /abc/ig.source // ...

  8. UML之关系

    学习UML我们首先要掌握他们的关系,UML关系可以分为四类,主要有关联.依赖.泛化和实现. 下面我们就一一来详细说明这几种关系. 关联 表示两个类或类与接口之间强烈的依赖关系,关联用直线表示.当然我们 ...

  9. 安装Android Studio开发环境

    下载安装包 中文社区官网 http://android-studio.org/ 目前最新的是2.3.3版本 安装Android Studio 双击安装 等待安装包自动解压 下一步 选择安装Androi ...

  10. 【Java】Eclipse+环境安装及新建Project

    安装Eclipse 1.进入ecilpse官方下载地址:https://www.eclipse.org/downloads/?FEATURED_STORY 2.点击红色箭头指向的Download Pa ...