一个C程序的基本组成要素
让我们来回顾一下上篇文章(详见:c语言编程:我的C语言源程序)中提到的程序,但是在这里要对这个程序做些改动。

|
/* 注释开始 ** file name : pun.c ** ** (C) 2013 Rongbing Tang ** ** This program prints a statement ** "To C, or not to C: that's not a problem." 注释结束 */
#include int main(void) { printf("To C, or not to C: that's not a problem.\n"); return 0; } |
这个程序,看起来简单,但是包含了一个C语言程序很多组成元素:空白和注释、预处理指令、函数、语句。
1.空白和注释
首先,需要注意的是程序的空白部分:空行将程序的不同部分分隔开;制表符(tab)用于语句的缩进,更好的显示程序的结构等。这里我采用的制表符是用了3个空格来作为一个制表符,在诸多的C编程实践中,3个空格的制表符是理想的,因为过多的空格制表会使得程序显得过于分散,过少的空格制表则会使得程序显得过于拥挤。
C语言是一种自由格式的语言,除了一些特定的规则外,其余部分并没有规则要求我们必须以怎样的格式书写程序。然而,采用一种约定俗成的格式来书写程序还是具有价值的 -- 使得程序的代码更加易于阅读和修改 -- 所以尽可能采用大多数人都采用的格式来书写程序。
其次,需要注意的就是注释:告诉程序的阅读者程序能做什么以及怎样做。
|
/* 注释开始 ** file name : pun.c ** ** (C) 2013 Rongbing Tang ** ** This program prints a statement ** "To C, or not to C: that's not a problem." 注释结束 */ |
这段文字就是注释,我在这段文字中注明了注释的开始和注释的结束。C语言中的注释以符号 /* 开始,以符号 */ 结束,符号中间的部分就是注释的本体。 在 C 程序中,凡是可以插入空白的地方都可以插入注释。
另外,在C语言中不允许在注释中嵌套的注释,因为注释的开头符号 /* 会跟一个遇到的 */ 符号组成一个注释,然后最后一个 */ 之前的部分因为语法错误就会使得程序不能通过编译。
在C语言的一些实现中,注释还有另外一种形式 -- 以符号 // 开始的当前行的后继部分为注释。这种风格的注释引自 C++语言,严格意义上并不是 ANSI C 标准中的一部分,所以某些 ANSI C 实现并不支持这种风格的注释。尽管这并不是ANSI C标准的一部分,但是这在一定程度上解决了C语言的注释不能嵌套的问题,尽管并不总是有效。
2.预处理指令
#include
上面这一行称为预处理指令,因为这些指令是由预处理器处理的。预处理器读入源代码,根据指令对源程序进行修改,然后把修改后的源代码交给编译器。预处理指令必须在单独成行,如果在一行上写不完一条预处理指令,则必须显示地用连接符号来连接写在不同行上的预处理指令代码。有关连接符号,会在以后的#define预处理指令介绍。
在这个例子中,预处理指令 #include
在stdio.h文件使我们可以访问标准I/O库(standard I/O libaray)中的函数,在标准I/O库中的函数用于执行输入输出的功能。
C语言中还有其它的预处理指令,这留在以后介绍。
3.函数
int main(void)
{
...
return 0;
}
上面这段文字就是一个主函数 main 函数。
函数,在数学上定义为:在一组对应关系下,从自变量出发,有且仅有一个唯一确定的值与之对应。在C语言中的函数则没有数学定义那么严格,在C语言中,函数就是:一个赋予了名称的模块,这个模块能完成一定的功能,这个模块由若干代码组成。
在上面这个main函数中, int 是main函数的返回值的类型;main是函数的名称,程序必须以函数名才能调用函数;(void)是参数列表,此参数列表表示参数列表为空,如果参数列表为空,在函数定义的时候必须显示地用关键字void来表示参数列表为空(有关参数列表将在后继介绍);{...}表示函数的主体部分,任何函数必须以 { 开头,以 } 结束, ... 表示函数体,如果函数体为空,即此函数什么也不做,则此函数为空函数,空函数用{}表示函数主体就行,当然空函数的定义和声明也是必须要注意的,以后会做介绍;如果一个函数有返回值的类型,则这个函数在函数体的结尾符号 } 前必须用 renturn语句来返回一个相对应的值,如果函数没有返回值的类型(或者说,返回值的类型为通用类型),则必须用关键字void来声明,而return 语句可以不附带返回值,甚至可以不使用return语句,因为程序在执行到当前模块的最后时会自动结束当前模块的执行并返回到某处。
在一个C程序中,有且仅有一个main函数。因为在C程序中,mian函数是程序的执行入口(或说为,程序的执行起点)。
4.语句
printf("To C, or not to C: that's not a problem.\n");
return 0;
上面这两行代码称为语句。
语句,就是程序在执行过程中执行的命令。
语句,分为:一般语句、复合语句。
一般语句,以分号作为结尾,上面的两行代码就是一般语句。一般语句又可以分为:函数调用语句、赋值语句、表达式语句、空语句等等。在这里只讨论两种语句:函数调用语句、return语句。
printf函数可用于产生完美的格式化输出到标准输出设备上,调用printf函数必须要有完整的函数名、参数列表,其中参数列表可以是不完整的,上面这个例子的printf函数调用的参数列表就是不完整的。正如上面提到的,有些函数是带有返回值类型的,而printf函数的返回值的类型就是int型(标准整数类型,有关标准整数类型在以后会介绍),如果printf调用执行成功后,会返回一个大于0的标准整数,如果调用执行失败了,则返回标准整数0。因此,对于某些函数,我们可以通过检测它的返回值来检测它是否成功被执行了。
return语句,用于结束某个模块的执行,并向某处返回。此例中,return语句出现在mian函数中,并返回了一个标准整数0,表示结束了main函数这个模块的执行,向操作系统返回了一个标准整数0,以便操作系统检测mian函数是否被成功执行了。
复合语句,使用{}括起来的若干条语句。复合语句在逻辑上被看作是一条语句,用于在逻辑上需要一条语句,但实际上一条语句无法满足要求的情况。
经过上面的介绍,现在我们可以对一个简单的C程序的形式做一个概括了。一个简单的C程序必须包含以下一个要素:
1.指令
2.mian函数
3.语句
如果我们采用C程序形式的结构来表示,则如下形式:
预处理指令
函数返回值类型说明 main(参数列表)
{
语句
}
如果一个程序出现了上面的组成要素,那么必须按照上面的顺序来组织它们。
另外值得注意的是,注释不是必须的,但是有用的。
思考:
1.如何在C程序中实现注释的嵌套?请随意写一个例子来证明的的实现。
2.预处理指令在整个程序的编译过程中如何被执行的?
3.如果上面的这个示例程序中没有使用#include
4.将示例程序进行改造,使main函数的返回值的类型为空。
题外话:
在早期的C语言实现中,某些编译器支持程序的“精简形式”,例如程序要调用printf函数时可以
不用显示地使用#include
所以为了能更好的阅读旧有的C程序源代码,学习了解旧C实现中某些特征还是很有必要的,这方面
的材料,建议阅读 K&R C 的第一版。
在学习C语言的过程,计算机硬件是一个很重要的部分,因为C语言是一种低级语言。有一种说法就
是 -- C语言是结构化的汇编语言。这种说法很形象,因为C语言的创立的初衷就是为了解决汇编语言
与计算机平台绑定的特性,但是又要使程序的执行效率接近汇编语言。当然,这是C编译器要做的事,
跟C语言没有直接联系,如果我想让JAVA这种执行效率低的语言的执行效率跟C语言一样,那么给JAVA
一个类似于C编译器的编译器,让JAVA称为编译执行的就行了。但是这么做了的话,JAVA还是JAVA么?
这个问题就当是本节的最后一个思考了。
当然,我们关心硬件时,主要关心内存,因为C语言的指令对内存的操作能力是C语言引以为傲的
地方,与其它语言极力向程序员隐藏与机器相关的细节有所不同,C语言的设计的思想就是将细节交
给程序员,并假设程序员清楚自己在干什么。这是一把双刃剑,所以使用C语言编写的程序很容易
出现内存泄露的问题,但这都是程序员造成的 -- 他们知道自己要干什么,却干的不够细致。
由于C语言过于包容,导致很多程序员并不真的想使用C语言来编写程序,所以产生许多类C语言
或者替代C语言的解决方案。尽管这些新的语言的编译器无法使其执行效率跟C一样,但对于如今不
断高速发展的计算机硬件来说,这也算是对这个问题的弥补了。唉,对于人类的“懒惰”,我们又能
做什么呢?只好为难那些为程序员提供编译器和设计计算机的科学家了。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/1052.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
