
2.2 声明
在程序中使用一个特定的标识符之前,我们必须给编译器一个声明C,指定该标识符应该代表什么。这是标识符与关键字的不同之处:关键字是由语言预定义的,不能声明或重新定义。
要点2.2 程序中的所有标识符都必须声明。
我们使用的三个标识符在程序中得到了有效的声明:main
、A
和i
。稍后,我们将看到其他标识符(printf
、size_t
和EXIT_SUCCESS
)来自何处。我们已经提到了main
函数的声明。这三个声明各自称为“仅仅是声明”,它们看起来是这样的:

这三个声明都遵循一种模式,每个都有一个标识符(main
、A
或i
)和一个与该标识符相关的特定属性的规范:
i
是size_t
类型C。main
后面是括号( ... )
,因此声明了一个int
类型的函数。A
后面是方括号[ ... ]
,因此声明的是一个数组C。数组是同一类型的若干项的集合,这里它由5
个double
类型的项组成。这5
项是按顺序排列的,可以通过数字引用,称为索引C,从0
到4
。
这些声明中每个都以一个类型C开头,这里是int
、double
和size_t
。稍后我们会看到它代表什么。就目前而言,只要知道这一点就足够了,即当在语句上下文中使用这三个标识符时,它们都将充当某种“数字”。
i
和A
声明了变量C,它们是允许我们存储值C的命名项。最好将它们想象成一种盒子,里面可能有某种特定类型的“东西”:

从概念上讲,区分盒子本身(对象)、规范(类型)、盒子内容(值)和写在盒子上的名称或标签(标识符)是很重要的。在图表中,如果我们不知道某项的实际值,就将其标记为??
。
对于其他三个标识符printf
、size_t
和EXIT_SUCCESS
,我们没有看到任何声明。实际上,它们是预先声明的标识符,但是正如我们在编译清单1.2时所看到的,关于这些标识符的信息并不是凭空而来的。我们必须告诉编译器在哪里可以获得关于它们的信息。这是在程序开始时完成的,即第2行和第3行:printf
是由stdio.h
提供的。而size_t
和EXIT_SUCCESS
则来自stdlib.h
。这些标识符的真正声明是在你的计算机上某个地方的.h
文件中指定的,它们可能是这样的:

因为这些预先声明的特性的细节不是很重要,所以这些信息通常隐藏在包含文件C或头文件C中。如果你需要了解它们的语义,那么在相应的文件中查找它们通常不是一个好主意,因为这些文件几乎是不可读的。相反,搜索平台附带的文档。对于那些勇敢的人,我总是建议他们看看当前的C标准,因为所有的信息都来源于此。对于缺乏勇气的人,以下命令可能会有所帮助:

声明只描述特性,而不创建它,因此重复声明不会造成太大危害,只会增加冗余。
要点2.3 标识符可以有多个一致的声明。
显然,如果同一标识符在程序的同一部分中有几个相互矛盾的声明,(对于我们或编译器来说)就会变得非常混乱,所以通常我们不允许这样做。C中“程序的同一部分”的含义是相当具体的:作用域C是程序的一部分,其中标识符是可见的C。
要点2.4 声明被绑定到它们所出现的作用域。
这些标识符的作用域由语法清楚地描述。在清单1.1中,我们有不同作用域的声明:
A
在main
的定义中是可见的,从它在第8行的声明开始,到24行包含该声明的{ ... }
块的结尾}
。i
的可见性较低。它被绑定到声明它的for
结构。它的可见性从第16行上的声明一直延伸到与第21行上的for
相关联的{ ... }
块的末尾。main
不包含在{ ... }
块中,因此从其声明开始直到文件结束都是可见的。
使用一下术语,前两种类型的作用域称为块作用域C,因为该作用域由匹配{ ... }
的块C所限制。第三种类型用于main
,它不在{ ... }
中,称为文件作用域C。文件作用域中的标识符通常被称为全局变量。