3.4 C数据类型

现在我们详细介绍C使用的基本数据类型。对于每种类型,我们介绍变量声明和常量定义的方法以及典型的用法。一些早期的C语言编译器不支持所有这些数据类型,所以请核查相关文档以了解可用的数据类型。

3.4.1 int类型

C提供多种整数类型。您可能不明白为什么一种类型不够用,答案是C为程序员提供了针对不同用途的多种选择。具体来讲,C的各种整数类型的区别在于所提供数值的范围,以及数值是否可以取负值。int类型是基本选择,您还可以根据任务和机器的特殊需求选择其他类型。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

int类型是有符号整数,即int类型的值必须是整数,可以是正的、负的或者是0,其取值范围依赖于计算机系统。一般地,int类型存储在计算机的一个字中。旧的IBM PC兼容机有16位的字,因而使用16位来存储一个int值,取值范围为-32768到32767。目前的个人计算机上的整数一般有32位,使用32位的int值,详见本章结尾处的表3.4。现在,个人计算机向着64位的处理器发展,自然而然将要使用更大的整数。ISO/ANSI C规定int类型的最小范围是-32768到32767。一般地,系统通过使用一个指示正负符号的特定位来表示有符号整数。第15章将讨论常用的方法。

一、声明int变量

在第2章“C语言概述”中您已经看到,int关键字用于声明基本的整数变量。书写格式为先写“int”,后加变量名,再加一个分号。要声明多个变量,可以逐个声明每个变量;也可以在int后跟上一个变量名列表,各个变量之间用逗号分隔。下面是正确的声明:

阅读 ‧ 电子书库

可以分别声明每个变量,也可以在一条语句中声明所有的4个变量。效果是一样的,都将为4个int大小的变量赋予名称并安排存储空间。

以上变量声明创建了变量但没有为其赋值。如何为变量赋值?前文已经出现了两种为变量赋值的方法。首先是直接赋值:

阅读 ‧ 电子书库

其次,可以通过scanf()这样的函数为变量赋值。下面介绍第三种方法。

二、初始化变量

初始化(initialize)变量就是为变量赋一个初始值。C语言中,可以在声明语句中初始化变量,即在变量名后跟上赋值运算符(=)和要赋给变量的值,如下所示:

阅读 ‧ 电子书库

最后一行中,只对cats进行了初始化。这种写法会让人误以为dogs也被初始化为94,所以最好避免在一个声明语句中同时出现初始化和未初始化变量。

简言之,声明语句为变量创建、标定存储空间并为其指定初始值,如图3.4所示。

阅读 ‧ 电子书库

图3.4 定义和初始化变量

三、int类型常量

上面例子中的整数21、32、14和94都是整数常量。C把不含小数点和指数的数当作整数,比如22和-44是整数常量,而22.0和2.2E1则不是。C把大多数整数常量看作int类型。如果整数特别大,则有不同的处理。详细信息请参见后面的“long常量和long long常量”小节中关于long int类型的介绍。

四、打印int值

可以使用printf()函数打印int类型的值。在第2章我们已经介绍过,%d符号用于指示在一行中的什么位置打印整数。%d被称为格式说明符(format specifier),因为它指示printf()应使用什么格式来显示一个数值。格式串中的每个%d都必须对应于打印项目列表中的一个int值。这个值可以是int变量、int常量或者其他的值为int类型的表达式。您必须确保格式说明符的数目同待打印值的数目相同,编译器不会发现这种类型的错误。程序清单3.2是一个简单的程序,它初始化一个变量,并且打印了这个变量的值、一个常量的值以及一个简单表达式的值。它也演示了当您粗心犯错时会导致什么结果。

程序清单3.2 print1.c程序

阅读 ‧ 电子书库

阅读 ‧ 电子书库

编译并运行上面的程序,则系统输出下列结果:

阅读 ‧ 电子书库

在第一行的输出语句中,第1个%d对应int变量ten,第2个%d对应int常量2,第3个%d对应int表达式ten-two的值。但第2次,程序使用ten为第1个%d提供打印值,然后使用内存中的任意值为其余的两个%d提供了打印值(您在运行该程序时获得的数值会不同于这里显示的数。不仅是因为内存中的内容可能不同,而且因为不同的编译器处理的内存位置不同)。

您可能会为编译器查不出这样明显的错误而烦恼,抱怨printf()的非常规设计。大多数函数有确切的参数数目,编译器可以检查数目是否正确。然而,printf()可以有1个、2个、3个或更多的参数,这使得编译器无法使用常规的方法检查错误。记住,使用printf()函数时,格式说明符的数目和要显示的值的数目一定要相同。

五、八进制和十六进制

一般地,C假设整数常量为十进制数,或者称为以10为基数的数。然而,很多程序员十分熟悉八进制(以8为基数)和十六进制(以16为基数)。因为8和16是2的幂(而10不是),所以这些数制可以更加方便地表示与计算机相关的值。例如,数字65536经常在16位机中出现,用十六进制表示它正好是10000。十六进制数每位恰好可由4位二进制数表示。例如,十六进制的数字3是0011,十六进制的数字5是0101。于是,十六进制值35的按位表示形式就是0011 0101,十六进制值53的按位表示形式就是0101 0011。这种对应关系使得十六进制和二进制(以2为基数)的表示法之间的转换非常方便。但是,计算机如何知道10000是十进制、十六进制还是八进制值呢?在C中,由专门的前缀指明哪一种进制。前缀0x或者0X表示使用十六进制值,所以16用十六进制表示为0x10或0X10。与之类似,前缀0(零)表示使用八进制。例如,十进制数16用八进制表示为020。关于进制,会在第15章详细介绍。

要清楚,这种使用不同数制系统的选择是为了方便而提供的,它并不影响数字的存储。无论16、020还是0×10,数字都按照同样的方式,即计算机内部使用的二进制编码进行存储。

六、显示八进制数和十六进制数

C既允许您使用3种数制书写数字,也允许以这3种数制显示数字。要用八进制而不是十进制显示整数,请用%0代替%d。要显示十六进制整数,请使用%x。如果想显示C语言前缀,可以使用说明符%#o%#x和%#X分别生成0、0x和0X前缀。程序清单3.3是一个简短的例子(回忆一下,您需要在一些为IDE而写的代码中插入一个getchar();语句,以便程序的执行窗口不会立即关闭)。

程序清单3.3 bases.c程序

阅读 ‧ 电子书库

编译并运行上面的程序,将产生下列输出

阅读 ‧ 电子书库

程序用3种不同的数制系统显示同一个值。printf()函数做了相关的转换。注意,要显示0和0x前缀,必须在说明符中加入#符号。

3.4.2 其他整数类型

初学语言时,int类型会满足您对整数的大多数需求。但为了给出完整的介绍,现在我们将讨论其他类型。您也可以跳过本节,直接阅读“使用字符:char类型”小节,在以后需要的时候再阅读本节。

C提供3个附属关键字修饰基本的整数类型:short、long和unsigned。应当记住以下几点:

● short int类型(或者简写为short类型)可能占用比int类型更少的存储空间,用于仅需小数值的场合以节省空间。同int类型一样,short类型是一种有符号类型。
● long int类型(或者简写为long类型)可能占用比int类型更多的存储空间,用于使用大数值的场合。同int类型一样,long类型是一种有符号类型。
● long long int类型(或者简写为long long类型(都是在C99标准中引入的),可能占用比long类型更多的存储空间,用于使用更大数值的场合。同int类型一样,long long类型是一种有符号类型。
● unsigned int类型(或者简写为unsigned类型)用于只使用非负值的场合。这种类型同有符号类型的表示范围不同。例如,16位的unsigned int取值范围为0到65535,而带符号int的取值范围为-32768到32767。由于指示数值正负的位也被用于二进制位,所以无符号数可以表示更大的数值。
● 在C90 标准中,还允许unsigned long int(简写为unsigned long)和unsigned short int(简写为unsigned short)类型。C99 又增加了unsigned long long int(简写为unsigned long long)类型。
● 关键字signed可以和任何有符号类型一起使用,它使数据的类型更加明确。例如:short、short int、signed short以及signed short int代表了同一种类型。

一、声明其他整数类型

其他整数类型的声明方式同int类型相同,下面是一些例子。一些早期的C语言编译器不识别最后3条语句,最后一条语句由C99标准最新引入。

阅读 ‧ 电子书库

二、使用多种整数类型的原因

为什么说long和short类型“可能”占用比int类型更多或者更少的存储空间呢?因为C仅保证short类型不会比int类型长,并且long类型不会比int类型短。这样做是为了适应不同的机器。例如,在一台运行Windows 3.1的IBM PC上,short类型和int类型都是16位,long类型是32位。而在一台Windows XP机器或Macintosh PowerPC上,short类型是16位,int类型和long类型都是32位。Pentium芯片和PowerPC G3或G4芯片的自然字大小都是32位,这使整数可以表示大于20亿的数(请参见表3.4)。在以上处理器和操作系统的组合中实现C时,实现者们认为没有表示更大数的需要,因此long类型使用和int类型同样的长度。很多场合不需要这么大的整数,因而创建了更节省空间的short类型。另一方面,早期的IBM PC中字长只有16位,这意味着在它上面的C实现需要比int类型更大的long类型。

现在64位处理器,如IBM Itanium、AMD Opteron和PowerPC G5正变得越来越普遍,需要64位的整数,因而引入long long类型。

目前一般的情况是,long long类型为64位,long类型为32位,short类型为16位,.int类型为16位或32位(依机器的自然字大小而定)。但原则上,这4种类型代表4个不同大小的数值。

C语言标准规定了每种基本数据类型的最小取值范围。对应于16位单位,short类型和int类型的最小取值范围为-32767到32767;对应于32位单位,long类型的最小取值范围为-2147483647到2147483647(注意,为了便于理解,这里使用了逗号,但是C代码中不允许这样)。对于unsigned short类型和unsigned int类型,最小取值范围为0到65535;对于unsigned long类型,最小取值范围为0到4294967295。long long类型是为了支持对64位的需求,最小取值范围是数目可观的-9223372036854775807到9223372036854775807;unsigned long long类型的最小取值范围为 0 到 18446744073709551615。如果您是在开支票,按照美国的写法这个数是18个百万的3次方,446个千的5次方,744个万亿,73个十亿,709个百万,551个千,和615。但谁会去数呢?

在诸多整数类型中选择哪一种呢?请首先考虑unsigned类型。把这种类型用于计数是十分自然的事,因为此时您不需要负数,而且无符号类型可以取得比有符号类型更大的正数。

当使用int类型不能表示一个数而使用long类型可以做到时,使用long类型。但是,在long类型大于int类型的系统中,使用long类型会减慢计算,所以没有必要时不要使用long类型。如果是在long类型等于int类型的系统中编写代码,当确实需要32位整数时,应使用long类型(而不是int类型),以便使程序被移植到16位机器上后仍然可以正常工作。

与之类似,如果需要64位整数,您应使用long long类型。一些计算机已经使用了 64位处理器,并且64位的服务器、工作站甚至桌面系统不久将十分普遍。

在int为32位的系统上,如果需要16位的值,那么使用short类型可以节省存储空间。通常,只有当程序使用了使系统可用内存很紧张的较大的整数数组时,节省存储空间才是重要的。使用short类型的另一个原因是计算机中的一些硬件寄存器是16位的。