现代C:概念剖析和编程实践
上QQ阅读APP看书,第一时间看更新

2.2 声明

在程序中使用一个特定的标识符之前,我们必须给编译器一个声明C,指定该标识符应该代表什么。这是标识符与关键字的不同之处:关键字是由语言预定义的,不能声明或重新定义。

要点2.2 程序中的所有标识符都必须声明。

我们使用的三个标识符在程序中得到了有效的声明:mainAi。稍后,我们将看到其他标识符(printfsize_tEXIT_SUCCESS)来自何处。我们已经提到了main函数的声明。这三个声明各自称为“仅仅是声明”,它们看起来是这样的:

024-01

这三个声明都遵循一种模式,每个都有一个标识符(mainAi)和一个与该标识符相关的特定属性的规范:

  • isize_t类型C
  • main后面是括号( ... ),因此声明了一个int类型的函数。
  • A后面是方括号[ ... ],因此声明的是一个数组C。数组是同一类型的若干项的集合,这里它由5double类型的项组成。这5项是按顺序排列的,可以通过数字引用,称为索引C,从04

这些声明中每个都以一个类型C开头,这里是intdoublesize_t。稍后我们会看到它代表什么。就目前而言,只要知道这一点就足够了,即当在语句上下文中使用这三个标识符时,它们都将充当某种“数字”。

iA声明了变量C,它们是允许我们存储C的命名项。最好将它们想象成一种盒子,里面可能有某种特定类型的“东西”:

025-01

从概念上讲,区分盒子本身(对象)、规范(类型)、盒子内容()和写在盒子上的名称或标签(标识符)是很重要的。在图表中,如果我们不知道某项的实际值,就将其标记为??

对于其他三个标识符printfsize_tEXIT_SUCCESS,我们没有看到任何声明。实际上,它们是预先声明的标识符,但是正如我们在编译清单1.2时所看到的,关于这些标识符的信息并不是凭空而来的。我们必须告诉编译器在哪里可以获得关于它们的信息。这是在程序开始时完成的,即第2行和第3行:printf是由stdio.h提供的。而size_tEXIT_SUCCESS则来自stdlib.h。这些标识符的真正声明是在你的计算机上某个地方的.h文件中指定的,它们可能是这样的:

025-02

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

025-03

声明只描述特性,而不创建它,因此重复声明不会造成太大危害,只会增加冗余。

要点2.3 标识符可以有多个一致的声明。

显然,如果同一标识符在程序的同一部分中有几个相互矛盾的声明,(对于我们或编译器来说)就会变得非常混乱,所以通常我们不允许这样做。C中“程序的同一部分”的含义是相当具体的:作用域C是程序的一部分,其中标识符是可见的C

要点2.4 声明被绑定到它们所出现的作用域。

这些标识符的作用域由语法清楚地描述。在清单1.1中,我们有不同作用域的声明:

  • Amain的定义中是可见的,从它在第8行的声明开始,到24行包含该声明的{ ... }块的结尾}
  • i的可见性较低。它被绑定到声明它的for结构。它的可见性从第16行上的声明一直延伸到与第21行上的for相关联的{ ... }块的末尾。
  • main不包含在{ ... }块中,因此从其声明开始直到文件结束都是可见的。

使用一下术语,前两种类型的作用域称为块作用域C,因为该作用域由匹配{ ... }C所限制。第三种类型用于main,它不在{ ... }中,称为文件作用域C。文件作用域中的标识符通常被称为全局变量