类型基础
作为程序员,我们熟悉使用变量来表示存储值的内存区域。在诸如C的类型化语言中,每个变量都必须使用类型声明。该类型告诉编译器我们期望在变量中存储的内容。然后,编译器既可以为此使用分配足够的空间,又可以检查程序员是否没有违反该类型的规则。在下面的示例中,我们看到为某些常见类型的变量分配空间的示例。
C99标准只提到了为C定义的每种类型的最小尺寸。这是因为在不同的处理器体系结构和操作系统中,用于类型的最佳尺寸可能会千差万别。为了完全安全,程序员永远不必假设任何变量的大小,但是,一个正常运行的系统显然需要就系统中将使用的大小类型达成协议。每个体系结构和操作系统都符合应用程序二进制接口或ABI。系统的ABI会在C标准与基础硬件和操作系统的要求之间填写详细信息。为特定的处理器和操作系统组合编写了ABI。
Type |
C99 minimum size (bits) |
Common size (32 bit architecture) |
char |
8 |
8 |
short |
16 |
16 |
int |
16 |
32 |
long |
32 |
32 |
long long |
64 |
64 |
Pointers |
Implementation dependent |
32 |
上面我们可以看到,与标准的唯一差异是int通常为32位,这是C99要求的最低16位的严格大小的两倍。指针实际上只是一个地址(即它们的值是一个地址,因此“指向”内存中的其他位置),因此指针需要足够的大小才能寻址系统中的任何内存。
64 bit
首先,这意味着所有指针必须为64位宽,以便它们可以表示系统中任何可能的地址。但是,系统实现者必须随后决定其他类型的大小。如下所示,广泛使用了两种常见的模型。
Type |
C99 minimum size (bits) |
Common size (LP64) |
Common size (Windows) |
char |
8 |
8 |
8 |
short |
16 |
16 |
16 |
int |
16 |
32 |
32 |
long |
32 |
64 |
32 |
long long |
64 |
64 |
64 |
Pointers |
Implementation dependent |
64 |
64 |
您可以看到,在LP64(长指针64)模型中,长值定义为64位宽。这与我们之前显示的32位模型不同。LP64模型广泛用于UNIX系统。在另一个模型中,long保留为32位值。这样可以保持与32码的最大兼容性。该模型与64位Windows一起使用。在两个模型中int的大小都没有增加到64位的理由很充分。考虑到如果将int的大小增加到64位,则程序员将无法获得32位变量。唯一可能的是将短裤重新定义为较大的32位类型。
64位变量太大,以至于通常不需要代表许多变量。例如,循环很少会重复超过32位变量(4294967296次!)所能容纳的次数。通常,对于红色,绿色和蓝色值,通常使用8位表示图像,对于额外的(alpha通道)信息,通常使用8位表示。总共32位。因此,在许多情况下,使用64位变量将浪费至少前32位(如果不是更多的话)。不仅如此,整数数组的大小现在也增加了一倍。这意味着程序将占用更多的系统内存(从而占用更多的缓存;在第3章,计算机体系结构中将详细讨论),而没有真正的改进。出于同样的原因,Windows选择将其long值保留为32位。由于大多数Windows API最初是为在32位系统上使用长变量而编写的,因此不需要额外的位,因此可以节省系统中的大量浪费空间,而无需重新编写所有API。
如果我们考虑提议的替代方法,其中short被重新定义为32位变量;在64位系统上工作的程序员可以将其用于他们知道限制在较小值上的变量。但是,当移回32位系统时,它们相同的short变量现在只有16位长,这个值实际上要溢出得多(65536)。通过让程序员在知道需要大的变量时请求更大的变量,就可移植性问题和浪费二进制空间达成了平衡。
类型限定符(Type Qualifiers)
C标准还讨论了变量类型的一些限定符例如const意味着一个变量将永远不会从其原始值被修改,而volatile则向编译器暗示该值可能会在程序执行流程之外发生变化,因此编译器必须注意不要以任何方式对访问进行重新排序。带符号和不带符号可能是两个最重要的限定词他们说变量是否可以取负值我们将在下面对此进行更详细的研究。
限定符都旨在将有关如何将变量用于编译器的额外信息这意味着两件事;编译器可以检查您是否违反了自己的规则(例如,写入const值),并且可以基于额外的知识进行优化(在后面的章节中进行了检查)。
标准类型
C99意识到所有这些规则,大小和可移植性问题很快就会变得非常混乱为了提供帮助,它提供了一系列特殊类型,可以指定变量的确切属性它们在<stdint.h>
中定义,格式为qtypes_t,其中q是限定符,type是基本类型,s是位宽度,_t
是扩展名,因此您知道您正在使用C99定义的类型。
因此,例如uint8_t是正好为8位宽的无符号整数定义了许多其他类型完整列表在C99 17.8或更详细(在头文件中)详细描述取决于实现C99标准的系统,您可以通过将它们映射到目标系统上适当大小的类型来为您提供这些类型在Linux上,这些标头由系统库提供。