5.2 基本类型

C有一系列的基本类型和构造派生类型C的方法,我们将在第6章中描述它们。

主要是由于历史的原因,基本类型的系统有点复杂,而且指定这些类型的语法也不是很直观。第一级规范完全由语言的关键字完成,比如signedintdouble。第一级主要根据C语言的内部结构来组织的。在此之上是通过头文件实现的第二级规范,我们已经看到了一些示例:size_tbool。第二级是按类型语义组织的,指定特定类型给程序员带来了什么属性。

我们将从这些类型的第一级规范开始。正如我们前面所讨论的(要点5.2),C语言中的所有基本值都是数字,但有不同种类的数字。作为一个主要的区别,我们有两类不同的数字,每一类都有两个子类:无符号整数C有符号整数C实浮点数C复浮点数C。这四个类中的每个都包含几个类型。根据表5.1按四个主要类型分类的基类型,它们是不同的。灰色背景的类型不支持算术运算,它们在做算术之前需要被提升char类型很特殊,因为它可以是无符号的,也可以是有符号的,这取决于平台。该表中的所有类型都被视为不同的类型,即使它们具有同样的类和精度。

它们的精度C决定了特定类型允许的值的合法范围[1]。表5.1概述了18种基类型。

表5.1 按四个主要类型分类的基类型

061-01

从表中可以看到,有六种类型不能直接用于算术运算,即所谓的窄类型C。在算术表达式中使用它们之前,需要将它们提升C到更广泛的类型之一。如今,在任何实际的平台上,这种提升是把同一值的signed int作为窄类型,而不管窄类型是否是有符号的。

要点5.10 在进行算术运算之前,窄整数类型被提升为signed int

注意,在窄整数类型中,我们有两个重要的成员:charbool。第一个是C的类型,它处理文本的可打印字符,第二个保存真值,falsetrue。正如我们之前所说,对于C来说,这些只是某种数字。

剩下的12个未提升的类型被分成了4类。

要点5.11 四个基类型的每一个都有三个不同的未提升类型。

与许多人认为的相反,C标准并没有规定这12种类型的精度:它只是限制了它们。它们依赖于许多由实现定义C的因素。

该标准规定的一件事情是,有符号类型值的范围必须根据其等级相互包括:

061-02

但这一包含并不需要很严格。例如,在许多平台上,intlong的值集合是相同的,尽管类型被认为是不同的。类似的包含有六种无符号类型:

061-03

但是请记住,对于任何算术或比较运算,窄无符号类型都会提升为signed int,而不是unsigned int,如图所示。

比较有符号类型和无符号类型的范围比较困难。显然,无符号类型永远不能包含有符号类型的负值。对于非负值,我们有以下包含相应等级的类型的值:

062-01

也就是说,对于给定的等级,有符号类型的非负值适合无符号类型。在任何现代平台上,这种包含都是严格的:无符号类型有不适合有符号类型的值。例如,一个常见的最大值对是231-1 =2147483 647(对于signed int)和232-1 = 4294967295(对于unsigned int)。

由于整型类型之间的相互关系依赖于平台,因此以一种可移植的方式为给定的目的选择“最佳”类型可能是一项烦琐的任务。幸运的是,我们可以从编译器实现中获得一些帮助,它为我们提供了typedef,比如表示某些特性的size_t

要点5.12 对大小、基数或序数使用size_t

请记住,无符号类型是最方便的类型,因为它们是唯一具有与数学属性定义一致的算术类型:模运算。它们不能在溢出时发出信号,但可以进行最佳优化。在5.7.1节中对它们有更详细的描述。

要点5.13 对不能为负的比较小的数使用unsigned

如果你的程序确实需要正值和负值,但是不能有分数值,那么就使用有符号类型(参见5.7.5节)。

要点5.14 对带有符号的比较小的数使用signed

要点5.15 对带有符号的比较大的差数使用ptrdiff_t

如果你想使用诸如0.53.77189E+89这样的值进行小数计算,请使用浮点类型(参见5.7.7节)。

要点5.16 对浮点计算使用double

要点5.17 对复杂计算使用double complex

C标准定义了许多其他类型,其中包括其他对特殊用例建模的算术类型,表5.2列出了其中一些。第二对表示平台支持的最大宽度类型。这也是预处理器执行各种算术或比较的类型。

表5.2 一些用于特定用例的语义算术类型

063-01

time_tclock_t这两种类型用于处理时间。它们是语义类型,因为不同平台的时间计算精度不同。以秒为单位的时间可以用于算术的方法是difftime函数:它计算两个时间戳的差。clock_t值表示平台的处理器时钟周期模型,因此时间单位通常远小于一秒。可以使用CLOCKS_PER_SEC将这些值转换为秒。


[1]这里使用的术语精度是受限制的,因为C标准定义了它。它不同于浮点计算的精度。