人们常说,C语言的声明太复杂了,的确,这也是C语言饱受批评的地方之一。不过,笔者认为,真正要受到批评的不是语言本身,而是那些传播者。传播者们通常都有一个共识:讲述要由浅入深。作为原则,笔者并非要反对它,毕竟笔者对C语言的学习,也经历了相同的过程。但是,由浅入深并不意味着一切从简,以偏盖全。计算机语言不同于数学理论(虽然它的确根植于数学,与数学密不可分),数学理论是一种循序渐进的过程,后面的理论以前面的理论为基础。但C语言归根说底,就是一堆语言规则而已,应该让学习者一开始就全面且详细地了解它,而不是象现在某些教材所做的那样,只说一部分,不说另一部分,以为这就是由浅入深了,实际上这是以偏盖全。
语言如此,声明作为C语言的一部分更是如此。我们最常见到的对声明的描述是这样的:
存储类别 类型限定词 类型 标识符
这种说明会给人们一种暗示:C语言的声明是静止的、死板的,什么声明都能够以这个为基础,往上一套就OK了。事实真的如此吗?说句心里话,笔者也祈祷事实真的如此,这样世界就简单多了、清静多了。但别忘了,这个世界总是让人事与愿违的。实际上,C的声明的组织形式是以嵌套为基础的,是用嵌套声明组织起来的,并非象上面所述那么死板,存储类说明符一定得放在限定词前面吗?类型说明符一定要紧贴标识符吗?不!C标准从来没有这样说过!下面来看一看C89对声明的形式是如何规定的:
声明:
声明说明符 初始化声明符表opt [opt的意思是option,可选]
其中声明说明符由以下三项构成:
声明说明符:
存储类说明符 声明说明符opt
类型说明符 声明说明符opt
类型限定符 声明说明符opt
在这里,一个声明说明符可以包含另一个声明说明符,这就是声明的嵌套,这种嵌套贯穿于整个声明之中,今天我们看来一个非常简单的声明,其实就是由多个声明嵌套组成的,例如:
static const int i=10, j=20, k=30;
变量i前面就是声明说明符部分,有三个声明说明符:static const int,static是一个存储类说明符,它属于这种形式:
static 声明说明符
static后面的声明说明符就是const int,const是一个类型限定符,这也是个嵌套,它是由
const 声明说明符
组成,最后的int是一个类型说明符,到这里已经没有嵌套了,int就是最底的一层。对于存储类说明符、类型说明符和类型限定符的排列顺序,C标准并没有规定其顺序,谁嵌套谁都可以。换言之,上面的声明可以写成:
int static const i=10, j=20, k=30;或者const int static i=10, j=20, k=30;
这无所谓,跟原声明是一样的。再举一个有趣的例子:
const int *p;与int const *p;
有些人会对后面一种形式感到困惑,因为他一直以来学习的都是那种死板的形式,因此他无法理解为什么那个const可以放在int的后面。实际上对于标准来说,这是再正常不过的行为了。
上面举的例子是变量的声明,函数的声明也同样道理,例如:
static const int func(void);
......
int main(void)
{
int static const (*p)(void);
p=func;
.........
return 0;
}
const int static func(void)
{
.......
return
0;
}
func的函数原型声明、函数定义跟main内的函数指针p的声明是一样的。但是,笔者并非鼓励大家把声明说明符写得乱七八糟,作为一个良好的风格,应该按照已经习惯约定的方式排列说明符,但懂得其中的原理非常重要。
声明static const int i=10, j=20, k=30;的int后面的部分就是初始化声明符表,这比较容易理解,这个符表实际上也是嵌套的:
初始化声明符表:
初始化声明符
初始化声明符表, 初始化声明符
初始化声明符:
声明符
声明符=初值
声明符是初始化声明符的主体,现在来讨论一下声明符是如何规定的:
声明符:
指针opt 直接声明符
这里写的指针opt指的是那个指针声明符*,要注意的是,*属于声明符,而不是声明说明符的一部分。
指针opt又包含:
指针:
* 类型限定符表opt
* 类型限定符表opt 指针
在这里有一个常见的问题,就是const int *p;与int * const p的区别,第一个声明的const属于声明说明符,它跟int一起,是用来说明*p这个声明符的,因此const修饰的是p所指向的那个对象,这个对象是const的。而第二个声明的const是声明符的一部分,它修饰的对象是p本身,因此p是const的。
上面规定的第二条值得注意,这条规定产生了一种指针与const的复杂形式,例如:
const int * const *** const ** const p;(是不是有种想冲向厕所的冲动?)这是一种复杂的声明嵌套,如何解读这种声明?其实只要掌握了它的规律,无论它有多少个const、多少个*都不难解读的,这个内容我将在第九章进行解释。
剩下的就是直接声明符和类型限定词表的内容:
直接声明符:
标识符
(声明符)
直接声明符[常量表达式opt]
直接声明符(形式参数类型表)
直接声明符(标识符表opt)
类型限定符表:
类型限定符
类型限定符表 类型限定符
这一章的最后一个内容,是讨论一下typedef,typedef用来声明一个别名,typedef后面的语法,是一个声明。本来笔者以为这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数。罪魁祸首又是那些害人的教材。在这些教材中介绍typedef的时候通常会写出如下形式:
typedef int PARA;
这种形式跟#define int PARA几乎一样,如前面几章所述,这些教材的宗旨是由浅入深,但实际做出来的行为却是以偏盖全。的确,这种形式在所有形式中是最简单的,但却没有对typedef进一步解释,使得不少人用#define的思维来看待typedef,把int与PARA分开来看,int是一部分,PARA是另一部分,但实际上根本就不是这么一回事。int与PARA是一个整体!就象int i:声明一样是一个整体声明,只不过int i定义了一个变量,而typedef定义了一个别名。这些人由于持有这种错误的观念,就会无法理解如下一些声明:
typedef int a[10];
typedef void (*p)(void);
他们会以为a[10]是int的别名,(*p)(void)是void的别名,但这样的别名看起来又似乎不是合法的名字,于是陷入困惑之中。实际上,上面的语句把a声明为具有10个int元素的数组的类型别名,p是一种函数指针的类型别名。
虽然在功能上,typedef可以看作一个跟int PARA分离的动作,但语法上typedef属于存储类声明说明符,因此严格来说,typedef int PARA整个是一个完整的声明。
发表评论
-
《再再论指针》后记
2011-03-02 11:25 680在这篇后记中,笔者将对三个问题进行补充: 一、 ... -
再再论指针----篇首语
2011-03-02 11:24 588指针是C语言规范 ... -
第十章 围绕p()与(*p)()的争论
2011-03-02 11:23 726对于一个函数: void func(void) ... -
第九章 指针与const
2011-03-02 11:22 700const一词是英文constan ... -
第八章 右左法则----复杂指针解析
2011-03-02 11:22 669上一章费那么多唇舌讨论C语言的声明,其实目的都是为了这一 ... -
第六章 “另类”数组
2011-03-02 11:20 800动态数组与字符串常量可算是两种“另类”数组。 ... -
第五章 指向数组的指针
2011-03-02 11:19 1096讲到第五章了,数组两个字还离不开我们的左右,数组的内容 ... -
第四章 [ ]运算符的本质
2011-03-02 11:18 754数组是存在于人们头 ... -
第三章 数组的解剖学
2011-03-02 11:17 606这一章我们来讨论 ... -
第二章 再一次吃惊----数组的数组与多维数组的区别
2011-03-02 11:17 512看见这个题目,也许有些人就会嘀咕了:难道两者不是一样的 ... -
第一章 什么是数组名?----一个让你吃惊的事实!
2011-03-02 11:15 728数组是指针的基础,多数人就是从数组的学习开始指针的旅程的 ... -
图书推荐
2011-02-19 19:04 820图书收藏夹 ...
相关推荐
《C语言详解》这本书是学习C语言的重要参考资料,它涵盖了C语言的基础到高级概念,适合初学者和有一定经验的程序员阅读。尽管书中可能存在没有跳转书签的不便,但这并不影响其作为一本深入理解C语言的教程的价值。 ...
《C语言详解(第5版)》是一本深入解析C语言的经典教材,由Jeri R. Hanly和Elliot B. Koffman合著,属于图灵计算机科学丛书中的一部。这本书以其详尽的解释、丰富的实例和严谨的讲解闻名,是学习C语言的重要参考资料...
### C语言指针详解 #### 一、引言 C语言作为一门强大的系统级编程语言,在计算机科学领域占据着极其重要的地位。其中,“指针”是C语言中最核心且复杂的一部分,也是许多初学者难以攻克的技术壁垒。指针在C语言中...
《实用C语言详解》这本书是针对C语言编程者的一份详尽指南,旨在帮助读者深入理解和熟练掌握C语言。C语言是一种广泛应用的编程语言,它以其高效、灵活和可移植性而闻名,广泛用于系统编程、嵌入式开发、软件开发等多...
### C语言指针详解 #### 一、引言 C语言是一种广泛使用的程序设计语言,以其高效、灵活而著称。在C语言中,指针是处理内存的强大工具,但同时也是最容易导致错误的地方之一。本篇文章将深入探讨C语言中的指针概念...
### C语言指针详解 #### 一、引言 C语言是一种广泛使用的程序设计语言,以其高效性和灵活性著称。其中,指针是C语言的一个重要特性,它为程序员提供了直接操控内存的能力,极大地增强了程序的功能性和性能。本文将...
c语言基础目录第一章 初识C语言1.C语言基础知识2.C语言的构成3.第一个C语言程序4.数据类型5.C的标识符5.1标识符的命名规则5.2标识符的分类6.变量6.1定义变量的方法6.2变量的分类 6.3变量的使用6.4变量的作用域和生命...
- 第七、八节:安排小组讨论或编程作业,提高协作和独立解决问题的能力。 - 课外活动:鼓励学生参与编程竞赛或项目,提升实战能力。 - 晚自习:学生自主学习,完成作业,教师提供答疑指导。 三、教案设计: 教案应...
### 彻底搞定C语言指针详解 #### 一、理解C语言中的指针概念 在C语言中,指针是一种非常重要的数据类型,它存储的是内存地址而非具体的数据值。掌握指针对于深入理解和高效编程至关重要。 ##### 1.1 内存地址与...
C语言函数库详解 C语言,作为一种强大的编程语言,其函数库是其核心部分,它提供了丰富的功能,帮助程序员高效地实现各种计算和任务。C语言的函数库分为标准库和非标准库,其中最常用的是标准库,也就是C语言标准...
【知识点详解】 1. **C语言特点**:C语言是一种结构化编程语言,以其简洁紧凑的语法、强大的功能和良好的可移植性著称。它允许程序员直接对硬件进行操作,因此在系统编程和嵌入式领域广泛应用。C语言的移植性好,...
### C语言第7章 数组知识点详解 #### 一、数组概述 数组是C语言中非常重要的一种数据类型,它能够帮助我们有效地管理一系列相同类型的数据。数组中的元素必须具有相同的类型,可以是一维的,也可以是多维的。 **...
### 第二章:C语言上机实验内容 这部分内容涵盖了C语言的基础到进阶知识点,通过一系列实验来帮助考生实践和巩固所学: #### 实验1:C程序的运行环境和运行方法 考生需要了解C程序的生命周期,包括编译、链接和...
### C语言指针详解 在计算机编程领域,尤其是在C语言中,指针是理解与高效操作内存的关键概念之一。本文将全面介绍C语言中的指针概念,并深入探讨其使用方法及注意事项。 #### 一、基本概念 在C语言中,指针是一...
7. **第7章_指针** C语言的指针是其强大之处,它允许直接操作内存。这一章将详细介绍指针的概念、声明、初始化,以及指针运算和指针与数组的关系。 8. **第8章_结构体与共用体** 结构体和共用体是C语言中的复杂...
在C语言中,结构体的声明、定义和初始化是基本操作。声明结构体时,我们通常使用struct关键字后跟结构体的名称和其中包含的成员。定义结构体时,会指定具体成员的类型和名称。初始化结构体,则是为结构体中的每个...
【C语言函数详解】 在C语言中,函数是程序的基本模块,它们负责执行特定的任务。函数分为两类:无参函数和有参函数。无参函数的一般形式是声明函数类型后跟着函数名,然后括号内是`void`,表明该函数不需要任何参数...