int类型

C语言提供了许多整数类型,为什么一种类型不够用?因为C语言让程序员针对不同情况选择不同的类型。特别是,C语言中的整数类型 可表示不同的取值范围和正负值。一般情况使用int类型即可,但是为满足特定任务和机器的要求,还可以选择其他类型。
int类型是有符号整型,即int类型的值必须是整数,可以是正整数、负整数或零。其取值范围依计算机系统而异。一般而言,储存一个int要占用一个机器字长。因此,早期的16位IBM PC兼容机使用16位来储存一个int值,其取值范围(即int值的取值范围)是-32768~32767。目前的个人计算机一般是32位,因此用32位储存一个int值。现在,个人计算机产业正逐步向着64位处理器发展,自然能储存更
大的整数。ISO C规定int的取值范围最小为-32768~32767。一般而言,系统用一个特殊位的值表示有符号整数的正负号。

八进制和十六进制

通常,C语言都假定整型常量是十进制数。然而,许多程序员很喜欢使用八进制和十六进制数。因为8和16都是2的幂,而10却不是。显然,八进制和十六进制记数系统在表达与计算机相关的值时很方便。例如,十进制数65536经常出现在16位机中,用十六进制表示正好是10000。另外,十六进制数的每一位的数恰好由4位二进制数表示。例如,十六进制数3的二进制数是0011,十六进制数5的二进制数是0101。因此,十六进制数35的位组合(bit pattern)是00110101,十六进制数53的位组合是01010011。这种对应关系使得十六进制和二进制的转换非常方便。但是,计算机如何知道10000是十进制、十六进制还是二进制?在C语言中,用特定的前缀表示使用哪种进制。0x或0X前缀表示十六进制值,所以十进制数16表示成十六进制是0x10或0X10。与此类似,0前缀表示八进制。例如,十进制数16表示成八进制是020。
要清楚,使用不同的进制数是为了方便,不会影响数被储存的方式。也就是说,无论把数字写成16、020或0x10,储存该数的方式都相同,因为计算机内部都以二进制进行编码。

显示八进制和十六进制

在C程序中,既可以使用也可以显示不同进制的数。不同的进制要使用不同的转换说明。以十进制显示数字,使用%d;以八进制显示数字,使用%o;以十六进制显示数字,使用%x。另外,要显示各进制数的前缀0、0x和0X,必须分别使用%#o、%#x、%#X。

其他整数类型

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

  • short int类型(或者简写为short)占用的存储空间可能比int类型少,常用于较小数值的场合以节省空间。与int类似,short是有符号类型。
  • long int或long占用的存储空间可能比int多,适用于较大数值 的场合。与int类似,long是有符号类型。
  • long long int或long long(C99标准加入)占用的储存空间可能比long多,适用于更大数值的场合。该类型至少占64位。与int 类似,long long是有符号类型。
  • unsigned int或unsigned只用于非负值的场合。这种类型与有符 号类型表示的范围不同。例如,16位unsigned int允许的取值范围是0~65535,而不是-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都表示同一种类型。

    整数溢出

    如果整数超出了相应类型的取值范围会怎样?下面分别将有符号类型和无符号类型的整数设置为比最大值略大,看看会发生什么(printf()函数使用%u说明显示unsigned int类型的值)。
    1. /* toobig.c-- 超出系统允许的最大int值*/
    2. #include <stdio.h>
    3. int main(void)
    4. {
    5. int i = 2147483647;
    6. unsigned int j = 4294967295;
    7. printf("%d %d %d\n", i, i+1, i+2);
    8. printf("%u %u %u\n", j, j+1, j+2);
    9. return 0;
    10. }
    在我们的系统下输出的结果是:
    1. 2147483647 -2147483648 -2147483647
    2. 4294967295 0 1
    可以把无符号整数j看作是汽车的里程表。当达到它能表示的最大值时,会重新从起始点开始。整数i也是类似的情况。它们主要的区别是,在超过最大值时,unsigned int类型的变量j从0开始;而int类型的变量i则从−2147483648开始。注意,当i超出(溢出)其相应类型所能表示的最大值时,系统并未通知用户。因此,在编程时必须自己注意这类问题。溢出行为是未定义的行为,C标准并未定义有符号类型的溢出规则。以上描述的溢出行为比较有代表性,但是也可能会出现其他情况。

    打印short、long、long long和unsigned类型

    打印unsigned int类型的值,使用%u转换说明;打印long类型的值,使用%ld转换说明。如果系统中int和long的大小相同,使用%d就行。但是,这样的程序被移植到其他系统(int和long类型的大小不同)中会无法正常工作。在x和o前面可以使用l前缀,%lx表示以十六进制格式打印long类型整数,%lo表示以八进制格式打印long类型整数。注意,虽然C允许使用大写或小写的常量后缀,但是在转换说明中只能用小写。
    C语言有多种printf()格式。对于short类型,可以使用h前缀。%hd表示以十进制显示short类型的整数,%ho表示以八进制显示short类型的整数。h和l前缀都可以和u一起使用,用于表示无符号类型。例如,%lu表示打印unsigned long类型的值。程序清单3.4演示了一些例子。对于支持long long类型的系统,%lld和%llu分别表示有符号和无符号类型。第

    使用字符:char类型

    char类型用于储存字符(如,字母或标点符号),但是从技术层面看,char是整数类型。因为char类型实际上储存的是整数而不是字符。计算机使用数字编码来处理字符,即用特定的整数表示特定的字符。美国最常用的编码是ASCII编码,本书也使用此编码。例如,在ASCII码中,整数65代表大写字母A。因此,储存字母A实际上储存的是整数65(许多IBM的大型主机使用另一种编码——EBCDIC,其原理相同。另外,其他国家的计算机系统可能使用完全不同的编码)。
    标准ASCII码的范围是0~127,只需7位二进制数即可表示。通常,char类型被定义为8位的存储单元,因此容纳标准ASCII码绰绰有余。许多其他系统(如IMB PC和苹果Macs)还提供扩展ASCII码,也在8位的表示范围之内。一般而言,C语言会保证char类型足够大,以储存系统(实现C语言的系统)的基本字符集。许多字符集都超过了127,甚至多于255。例如,日本汉字(kanji)字符集。商用的统一码(Unicode)创建了一个能表示世界范围内多种字符集的系统,目前包含的字符已超过110000个。国际标准化组织(ISO)和国际电工技术委员会(IEC)为字符集开发了ISO/IEC 10646标准。统一码标准也与ISO/IEC 10646标准兼容。
    C语言把1字节定义为char类型占用的位(bit)数,因此无论是16位还是32位系统,都可以使用char类型。

    字符常量和初始化

    如果要把一个字符常量初始化为字母A,不必背下ASCII码,用计算机语言很容易做到。通过以下初始化把字母A赋给grade即可:
    char grade = 'A';
    在C语言中,用单引号括起来的单个字符被称为字符常量(character constant)。编译器一发现’A’,就会将其转换成相应的代码值。单引号必不可少。下面还有一些其他的例子:
    char broiled; /* 声明一个char类型的变量 */
    broiled = 'T'; /* 为其赋值,正确 */
    broiled = T; /* 错误!此时T是一个变量 */
    broiled = "T"; /* 错误!此时"T"是一个字符串 */
    如上所示,如果省略单引号,编译器认为T是一个变量名;如果把T用双引号括起来,编译器则认为”T”是一个字符串。
    实际上,字符是以数值形式储存的,所以也可使用数字代码值来赋值:
    char grade = 65; /* 对于ASCII,这样做没问题,但这是一种不好的编程风格 */
    在本例中,虽然65是int类型,但是它在char类型能表示的范围内,所以将其赋值给grade没问题。由于65是字母A对应的ASCII码,因此本例是把A赋给grade。注意,能这样做的前提是系统使用ASCII码。其实,用’A’代替65才是较为妥当的做法,这样在任何系统中都不会出问题。因此,最好使用字符常量,而不是数字代码值。

奇怪的是,C语言将字符常量视为int类型而非char类型。例如,在int为32位、char为8位的ASCII系统中,有下面的代码:
char grade = 'B';
本来’B’对应的数值66储存在32位的存储单元中,现在却可以储存在8位的存储单元中(grade)。利用字符常量的这种特性,可以定义一个字符常量’FATE’,即把4个独立的8位ASCII码储存在一个32位存储单元中。如果把这样的字符常量赋给char类型变量grade,只有最后8位有效。因此,grade的值是’E’。

非打印字符

单引号只适用于字符、数字和标点符号,浏览ASCII表会发现,有些ASCII字符打印不出来。例如,一些代表行为的字符(如,退格、换行、终端响铃或蜂鸣)。C语言提供了3种方法表示这些字符。

第1种方法前面介绍过——使用ASCII码。例如,蜂鸣字符的ASCII值是7,因此可以这样写:
char beep = 7;
第2种方法是,使用特殊的符号序列表示一些特殊的字符。这些符号序列叫作转义序列(escape sequence)。表3.2列出了转义序列及其含义。
把转义序列赋给字符变量时,必须用单引号把转义序列括起来。例如,假设有下面一行代码:
char nerf = '\n';
稍后打印变量nerf的效果是,在打印机或屏幕上另起一行。

转义序列 含义
\a 警报
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ 反斜杠
\‘ 单引号
\“ 双引号
\? 问号
\0oo 八进制值(oo必须是有效的八进制数,即每个o可表示0~7中的一个数)
\xhh 十六进制(hh必须是有效的十六进制数,即每个h可表示0~f中的一个数)

_Bool类型

C99标准添加了_Bool类型,用于表示布尔值,即逻辑值true和false。因为C语言用值1表示true,值0表示false,所以_Bool类型实际上也是一种整数类型。但原则上它仅占用1位存储空间,因为对0和1而言,1位的存储空间足够了。

float、double 和 long double

各种整数类型对大多数软件开发项目而言够用了。然而,面向金融和数学的程序经常使用浮点数。C语言中的浮点类型有float、double和long double类型。它们与FORTRAN和Pascal中的real类型一致。 前面提到过,浮点类型能表示包括小数在内更大范围的数。浮点数的表示类似于科学记数法(即用小数乘以10的幂来表示数字)。该记数系统常用于表示非常大或非常小的数。
记数法实例

数字 科学计数法 指数计数法
1000000000 1.0*109 1.0e9
123000 1.23*105 1.23e5
322.56 3.2256×102 3.2256e2
0.000056 5.6×10-5 5.6e-5

第1列是一般记数法;第2列是科学记数法;第3列是指数记数法(或称为e记数法),这是科学记数法在计算机中的写法,e后面的数字代表10的指数。

C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是10-37~10+37。前一项规定指float类型必须能够表示33.333333的前6位数字,而不是精确到小数点后6位数字。后一项规定用于方便地表示诸如太阳质量(2.0e30千克)、一个质子的电荷量(1.6e-19库仑)或国家债务之类的数字。通常,系统储存一个浮点数要占用32位。其中8位用于表示指数的值和符号,剩下24位用于表示非指数部分(也叫作尾数或有效数)及其符号。
C语言提供的另一种浮点类型是double(意为双精度)。double类型和float类型的最小取值范围相同,但至少必须能表示10位有效数字。一般情况下,double占用64位而不是32位。一些系统将多出的32位全部用来表示非指数部分,这不仅增加了有效数字的位数(即提高了精度),而且还减少了舍入误差。另一些系统把其中的一些位分配给指数部分,以容纳更大的指数,从而增加了可表示数的范围。无论哪种方法,double类型的值至少有13位有效数字,超过了标准的最低位数规定。
C语言的第3种浮点类型是long double,以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。

打印浮点型

printf()函数使用%f转换说明打印十进制记数法的float和double类型浮点数,用%e打印指数记数法的浮点数。如果系统支持十六进制格式的浮点数,可用a和A分别代替e和E。打印long double类型要使用%Lf、%Le或%La转换说明。给那些未在函数原型中显式说明参数类型的函数(如,printf())传递参数时,C编译器会把float类型的值自动转换成double类型。

  1. /* showf_pt.c -- 以两种方式显示float类型的值 */
  2. #include <stdio.h>
  3. int main(void)
  4. {
  5. float aboat = 32000.0;
  6. double abet = 2.14e9;
  7. long double dip = 5.32e-5;
  8. printf("%f can be written %e\n", aboat, aboat); // 下一行要求编译器支持C99或其中的相关特性
  9. printf("And it's %a in hexadecimal, powers of 2 notation\n", aboat);
  10. printf("%f can be written %e\n", abet, abet);
  11. printf("%Lf can be written %Le\n", dip, dip);
  12. return 0;
  13. }

该程序的输出如下,前提是编译器支持C99/C11:

  1. 32000.000000 can be written 3.200000e+04
  2. And it's 0x1.f4p+14 in hexadecimal, powers of 2 notation
  3. 2140000000.000000 can be written 2.140000e+09
  4. 0.000053 can be written 5.320000e-05

实数和虚数类型

许多科学和工程计算都要用到复数和虚数。C99标准支持复数类型和虚数类型,但是有所保留。一些独立实现,如嵌入式处理器的实现,就不需要使用复数和虚数(VCR芯片就不需要复数)。一般而言,虚数类型都是可选项。C11标准把整个复数软件包都作为可选项。
简而言之,C语言有3种复数类型:float_Complex、double_Complex和long double_Complex。例如,float _Complex类型的变量应包含两个float类型的值,分别表示复数的实部和虚部。类似地,C语言的3种虚数类型是float _Imaginary、double_Imaginary和long double _Imaginary。如果包含complex.h头文件,便可用complex代替_Complex,用imaginary代替_Imaginary,还可以用I代替-1的平方根。为何C标准不直接用complex作为关键字来代替_Complex,而要添加一个头文件(该头文件中把complex定义为_Complex)?因为标准委员会考虑到,如果使用新的关键字,会导致以该关键字作为标识符的现有代码全部失效。例如,之前的C99,许多程序员已经使用struct complex定义一个结构来表示复数或者心理学程序中的心理状况(关键字struct用于定义能储存多个值的结构,详见第14章)。让complex成为关键字会导致之前的这些代码出现语法错误。但是,使用struct_Complex的人很少,特别是标准使用首字母是下划线的标识符作为预留字以后。因此,标准委员会选定_Complex作为关键字,在不用考虑名称冲突的情况下可选择使用complex。

小结:基本数据类型

关键字:
基本数据类型由11个关键字组成:int、long、short、unsigned、char、float、double、signed、_Bool、_Complex和_Imaginary.
有符号整型:
有符号整型可用于表示正整数和负整数。

  • int ——系统给定的基本整数类型。C语言规定int类型不小于16位。
  • short或short int ——最大的short类型整数小于或等于最大的int类型整数。C语言规定
  • short类型至少占16位。
  • long或long int ——该类型可表示的整数大于或等于最大的int类型整数。C语言规定
  • long类型至少占32位。
  • long long或long long int ——该类型可表示的整数大于或等于最大的long类型整数。long long类型至少占64位。

一般而言,long类型占用的内存比short类型大,int类型的宽度要么和long类型相同,要么和short类型相同。例如,旧DOS系统的PC提供16位的short和int,以及32位的long;Windows 95系统提供16位的short以及32位的int和long。
无符号整型:
无符号整型只能用于表示零和正整数,因此无符号整型可表示的正整数比有符号整型的大。在整型类型前加上关键字unsigned表明该类型是无符号整型:unsigned int、unsigned long、unsigned short。单独的unsigned相当于unsigned int。
字符类型:
可打印出来的符号(如A、&和+)都是字符。根据定义,char类型表示一个字符要占用1字节内存。出于历史原因,1字节通常是8位,但是如果要表示基本字符集,也可以是16位或更大。

  • char ——字符类型的关键字。有些编译器使用有符号的char,而有些则使用无符号的char。在需要时,可在char前面加上关键字signed或unsigned来指明具体使用哪一种类型。

布尔类型:
布尔值表示true和false。C语言用1表示true,0表示false。

  • _Bool ——布尔类型的关键字。布尔类型是无符号int类型,所占用的空间只要能储存0或1即可。

实浮点类型:实浮点类型可表示正浮点数和负浮点数。

  • float ——系统的基本浮点类型,可精确表示至少6位有效数字。
  • double ——储存浮点数的范围(可能)更大,能表示比float类型更多的有效数字(至少10位,通常会更多)和更大的指数。
  • long double ——储存浮点数的范围(可能)比double更大,能表示比double更多的有效数字和更大的指数。

复数和虚数浮点数:
虚数类型是可选的类型。复数的实部和虚部类型都基于实浮点类型来构成:

  • float _Complex
  • double _Complex
  • long double _Complex
  • float _Imaginary
  • double _Imaginary
  • long double _Imaginary

    小结:如何声明简单变量

    1.选择需要的类型
    2.使用有效的字符给变量起一个变量名。
    3.按以下格式进行声明:
    类型说明符 变量名;
    类型说明符由一个或多个关键字组成。下面是一些示例:
    int erest;
    unsigned short cash;
    4.可以同时声明相同类型的多个变量,用逗号分隔各变量名,如下所示:
    char ch,init,ans;
    5.在声明的同时还可以初始化变量
    float mass = 6.0E24;