① 从C99开始引入。②从C11开始引入。
因为C语言是区分大小写的,所以程序中出现的关键字必须严格按照表2-1所示的那样采用小写字母。标准库中函数(如printf)的名字也只能包含小写字母。某些可怜的程序员用大写字母输入了整个程序,结果发现编译器不能识别关键字和库函数的调用。应该避免这类情况发生。
请注意有关标识符的其他限制。某些编译器把特定的标识符(如asm)视为附加关键字。属于标准库的标识符也是受限的(➤21.1节)。误用这些名字可能会导致编译或链接出错。以下划线开头的标识符也是受限的。2.8 C程序的书写规范
我们可以把C程序看成一连串记号(token),即许多在不改变意思的情况上无法再分割的字符组。标识符和关键字都是记号。像 和-这样的运算符、逗号和分号这样的标点符号以及字面串,也都是记号。例如,语句
printf("Height: %d\n", height);
是由7个记号组成的:
printf ( "Height: %d\n" , height ) ; ① ② ③ ④ ⑤ ⑥ ⑦
其中记号①和记号⑤是标识符,记号③是字面串,记号②、记号④、记号⑥和记号⑦是标点符号。
大多数情况下,程序中记号之间的空格数量没有严格要求。除非两个记号合并后会产生第三个记号,否则在一般情况下记号之间根本不需要留有间隔。例如,可以删除2.6节的程序celsius.c中的大多数间隔,只保留诸如int和main之间以及float和fahrenheit之间的空格。
/* Converts a Fahrenheit temperature to Celsius */ #include <stdio.h> #define FREEZING_PT 32.0f #define SCALE_FACTOR (5.0f/9.0f) int main(void){float fahrenheit,celsius;printf( "Enter Fahrenheit temperature: ");scanf("%f", &fahrenheit); celsius=(fahrenheit-FREEZING_PT)*SCALE_FACTOR; printf("Celsius equivalent: %.1f\n", celsius);return 0;}
事实上,如果这个页面足够宽,可以将整个main函数都放在一行中。但是,不能把整个程序写在一行内,因为每条预处理指令都要求独立成行。
当然,用这种方式压缩程序并不是个好主意。事实上,添加足够的空格和空行可以使程序更便于阅读和理解。幸运的是,C语言允许在记号之间插入任意数量的间隔,这些间隔可以是空格符、制表符和换行符。这一规则对于程序布局有如下积极意义。
-
语句可以分开放在任意多行内。例如,下面的语句非常长,很难将它压缩在一行内:
printf("Dimensional weight (pounds): %d\n", (volume INCHES_PER_POUND - 1) / INCHES_PER_POUND);
-
记号间的空格使我们更容易区分记号。基于这个原因,我通常会在每个运算符的前后都放上一个空格:
volume = height * length * width;
此外,我还会在每个逗号后边放一个空格。某些程序员甚至在圆括号和其他标点符号的两边都加上空格。
-
缩进有助于轻松识别程序嵌套。
例如,为了清晰地表示出声明和语句都嵌套在main函数中,应该对它们进行缩进。 - 空行可以把程序划分成逻辑单元,从而使读者更容易辨别程序的结构。没有空行的程序很难阅读,就像不分章节的书一样。
2.6节中的程序celsius.c体现了上面提到的几种布局方法。我们来仔细阅读一下这个程序中的main函数:
int main(void) { float fahrenheit, celsius; printf("Enter Fahrenheit temperature: "); scanf("%f", &fahrenheit); celsius = (fahrenheit - FREEZING_PT) * SCALE_FACTOR; printf("Celsius equivalent: %.1f\n", celsius); return 0; }
首先,观察一下运算符=、-和*两侧的空格是如何使这些运算符凸显出来的;其次,留心为了明确声明和语句属于main函数,如何对它们采取缩进格式;最后,注意如何利用空行将main划分为5部分:(1) 声明变量fahrenheit和celsius;(2) 获取华氏温度;(3) 计算变量celsius的值;(4) 显示摄氏温度;(5) 返回操作系统。
在讨论程序布局问题的同时,还要注意一下记号{和记号}的放置方法:记号{放在了main()的下面,而与之匹配的记号}则放在了独立的一行中,并且与记号{排在同一列上。把记号}独立地放在一行中可以便于在函数的末尾插入或删除语句,而将记号}与记号{排在一列上是为了便于找到main函数的结尾。
最后要注意:虽然可以在记号之间添加额外的空格,但是绝不能在记号内添加空格,否则可能会改变程序的意思或者引发错误。如果写成
fl oat fahrenheit, celsius; /*** WRONG ***/
或
fl oat fahrenheit, celsius; /*** WRONG ***/
在程序编译时会报错。尽管把空格加在字面串中会改变字符串的意思,但这样做是允许的。然而,把换行符加进字符串中(换句话说,就是把字符串分成两行)却是非法的:
printf("To C, or not to C: that is the question.\n"); /*** WRONG ***/
把字符串从一行延续到下一行(➤13.1节)需要一种特殊的方法才可以实现。这种方法将在稍后的章节中学到。
问与答
问:GCC是什么的简称?(p.8)
答:GCC最初是GNU C Compiler的简称,现在指GNU Compiler Collection,这是因为最新版本的GCC能够编译用Ada、C、C 、Fortran、Java和Objective-C等多种语言编写的程序。
问:明白了,但GNU又是什么意思呢?
答:GNU指的是“GNU's Not UNIX!”(发音为guh-NEW),它是自由软件基金会(Free Software Foundation)的一个项目。自由软件基金会是由Richard M. Stallman发起的一个组织,旨在抗议对UNIX软件授权的各种限制。从它的网站可以看出,自由软件基金会认为用户应该可以自由地“运行、复制、发布、研究、改变和改进”软件。GNU项目从头开始重写了许多传统的UNIX软件,并使公众能够免费地获得。
GCC和其他GNU软件对于Linux操作系统来说是至关重要的。Linux本身只是操作系统的“内核”(处理程序调度和基本输入/输出服务的部分),为了获得具备完整功能的操作系统,GNU软件是必要的。
GNU网站提供了更多有关GNU项目的信息。
问:GCC有什么过人之处呢?
答:我们说GCC重要,不仅仅是因为它能免费获取、能编译很多语言。GCC还可以在许多操作系统下运行,并为多种CPU生成代码(支持所有广为使用的操作系统和CPU)。GCC是许多基于UNIX的操作系统(包括Linux、BSD和Mac OS X)的主要编译器,并广泛用于商业软件开发。有关GCC的更多信息请参考GCC网站。
问:GCC发现程序中错误的能力如何?
答:GCC有多个命令行选项来控制程序检查的彻底程度。使用这些选项可以帮助我们有效地找出程序中潜在的故障区域。下面是一些比较常用的选项。
这些选项常常可以结合使用:
% gcc –O –Wall –W –pedantic –std=c99 –o pun pun.c
问:为什么C语言如此简明扼要?如果在C语言中用begin和end代替{和},用integer代替int,等等,程序似乎更加易读。(p.9)
答:据说,C程序的简洁性是由开发该语言时贝尔实验室的环境造成的。第一个C语言编译器是运行在DEC PDP-11计算机(一种早期的小型计算机)上的,而程序员用电传打字机(实际上是一种与计算机相连的打字机)输入程序和打印列表。因为电传打字机的速度非常慢(每秒钟只能打出10个字符),所以在程序中尽量减少字符数量显然是十分有利的。
问:在某些C语言书中,main函数的结尾使用的是exit(0)而不是return 0,二者是否一样呢?(p.10)
答:当出现在main函数中时,这两种语句是完全等价的:二者都终止程序执行,并且向操作系统返回0值。使用哪种语句完全依据个人喜好而定。
问:如果main函数末尾没有return语句会产生什么后果?(p.10)
答:return语句不是必需的;如果没有return语句,程序一样会终止。在C89中,返回给操作系统的值是未定义的。