- 现代C:概念剖析和编程实践
- (德)延斯·古斯泰特
- 1716字
- 2025-04-08 00:44:19
5.2 基本类型
C有一系列的基本类型和构造派生类型C的方法,我们将在第6章中描述它们。
主要是由于历史的原因,基本类型的系统有点复杂,而且指定这些类型的语法也不是很直观。第一级规范完全由语言的关键字完成,比如signed
、int
和double
。第一级主要根据C语言的内部结构来组织的。在此之上是通过头文件实现的第二级规范,我们已经看到了一些示例:size_t
和bool
。第二级是按类型语义组织的,指定特定类型给程序员带来了什么属性。
我们将从这些类型的第一级规范开始。正如我们前面所讨论的(要点5.2),C语言中的所有基本值都是数字,但有不同种类的数字。作为一个主要的区别,我们有两类不同的数字,每一类都有两个子类:无符号整数C、有符号整数C、实浮点数C和复浮点数C。这四个类中的每个都包含几个类型。根据表5.1按四个主要类型分类的基类型,它们是不同的。灰色背景的类型不支持算术运算,它们在做算术之前需要被提升。char
类型很特殊,因为它可以是无符号的,也可以是有符号的,这取决于平台。该表中的所有类型都被视为不同的类型,即使它们具有同样的类和精度。
它们的精度C决定了特定类型允许的值的合法范围[1]。表5.1概述了18种基类型。
表5.1 按四个主要类型分类的基类型

从表中可以看到,有六种类型不能直接用于算术运算,即所谓的窄类型C。在算术表达式中使用它们之前,需要将它们提升C到更广泛的类型之一。如今,在任何实际的平台上,这种提升是把同一值的signed int
作为窄类型,而不管窄类型是否是有符号的。
要点5.10 在进行算术运算之前,窄整数类型被提升为signed int
。
注意,在窄整数类型中,我们有两个重要的成员:char
和bool
。第一个是C的类型,它处理文本的可打印字符,第二个保存真值,false
和true
。正如我们之前所说,对于C来说,这些只是某种数字。
剩下的12个未提升的类型被分成了4类。
要点5.11 四个基类型的每一个都有三个不同的未提升类型。
与许多人认为的相反,C标准并没有规定这12种类型的精度:它只是限制了它们。它们依赖于许多由实现定义C的因素。
该标准规定的一件事情是,有符号类型值的范围必须根据其等级相互包括:

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

但是请记住,对于任何算术或比较运算,窄无符号类型都会提升为signed int
,而不是unsigned int
,如图所示。
比较有符号类型和无符号类型的范围比较困难。显然,无符号类型永远不能包含有符号类型的负值。对于非负值,我们有以下包含相应等级的类型的值:

也就是说,对于给定的等级,有符号类型的非负值适合无符号类型。在任何现代平台上,这种包含都是严格的:无符号类型有不适合有符号类型的值。例如,一个常见的最大值对是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.5
或3.77189E+89
这样的值进行小数计算,请使用浮点类型(参见5.7.7节)。
要点5.16 对浮点计算使用double
。
要点5.17 对复杂计算使用double complex
。
C标准定义了许多其他类型,其中包括其他对特殊用例建模的算术类型,表5.2列出了其中一些。第二对表示平台支持的最大宽度类型。这也是预处理器执行各种算术或比较的类型。
表5.2 一些用于特定用例的语义算术类型

time_t
和clock_t
这两种类型用于处理时间。它们是语义类型,因为不同平台的时间计算精度不同。以秒为单位的时间可以用于算术的方法是difftime
函数:它计算两个时间戳的差。clock_t
值表示平台的处理器时钟周期模型,因此时间单位通常远小于一秒。可以使用CLOCKS_PER_SEC
将这些值转换为秒。
[1]这里使用的术语精度是受限制的,因为C标准定义了它。它不同于浮点计算的精度。