第七章 基本类型
整型
C语言支持两种根本不同的数值类型:整型和浮点型。整型的值都是数,而浮点型可能还有小数部分。整型还分为有符号的和无符号的。
Note
在有符号数中,如果数为正数或零,那么最左边的位(符号位)为0,如果是负数,符号位则为1。默认情况下,C语言中的整型变量都是有符号的。
C语言提供了不同尺寸的整型, int 是正常的尺寸。可以指明变量是 long 型或 short 型, signed 型或 unsigned 型。可以有这些类型组合:
short int, unsigned short int, int, unsigned int, long int, unsigned long int
可以把 int 省略掉,即 short int 可以写成 short 。
不同类型的整型表示的取值范围根据机器的不同而不同。
整型常量
这里说的常量表示在程序中以文本形式显示的数。C语言允许用十进制、八进制和十六进制形式书写整型常量。
十进制常量包含数字0~9
,但是一定不能以零开头:15 255 32767
八进制常量只包含数字0~7
,但是必须以零开头:017 0377 07777
十六进制常量包含数字0~9和字母a~f,而且总是以0x开头:0xf 0xff 0xffff
当程序中出现整型常量时,如果它属于 int 类型的取值范围,那么编译器会把此常量作为普通整数来处理,否则作为长整型处理。为了迫使编译器把常量作为长整型来处理,只需在后边加上一个字母L:15L
为了指明是无符号常量,可以在常量后边加上字母U:15U
还可以把UL写在一起:0xffffUL
读写整数
读写无符号、短的或长的整数需要一些新的转换说明符。
- 读写无符号整数时,使用字母u、o或x代替转换说明符d。u代表十进制、o八进制、x十六进制。
- 读写短整数时,在d、o、u或x前面加字母h。
- 读写长整型时,在d、o、u或x前面加字母l。
浮点型
有时候需要变量存储带有小数的数,或者能存储极大数或极小数。这类数可以用浮点格式进行存储(因小数点是浮动的而得名)。C语言提供3种浮点型,它们对应不同的浮点格式:
- float :单精度浮点数
- double :双精度浮点数
- long double :扩展双精度浮点数
浮点常量
浮点常量有许多书写方式:57.0 57. 57E0 5.7E1
用指数表示的是10的幂。
默认情况下,浮点常量都以 double 的形式存储。为了表明只需要单精度,可以在常量的末尾处加上字母f,如 57.0f 。
读写浮点数
转换说明符 %e %f 和 %g 用于读写单精度浮点数,当读取 double 时,需要用 %lf ,而写 double 时,不需要加l。
字符型
给 char 类型的变量赋值:
char ch;
ch = 'a';
C语言会按小整数的方式处理字符。
转义序列
一些特殊的符号无法书写,比如换行符,这时候需要用C语言提供的特殊符号转义序列( escape sequence )。
转义序列分成两种:字符转义序列和数字转义序列。
字符处理函数
可以使用 toupper 库函数把小写字母转成大写字母:
ch = toupper(ch);
被调用时,函数检查参数是否是小写字母,如果是,那么将它转换成大写字母,否则,函数返回参数的值。
读写字符
转换说明符 %c 允许 scanf 函数和 printf 函数对单独一个字符进行读写操作。
char c;
scanf("%c", &c);
printf("%c", c);
在读入字符前, scanf 不会跳过空白字符。为了强制 scanf 函数在读入字符前跳过空白字符,需要在格式串转换说明符 %c 前面加上一个空格。
char c;
scanf(" %c", &c);
C语言还提供了读写单独字符的其他方法。可以使用 getchar 和 putchar 函数来替代调用 scanf 函数和 printf 函数。每次调用 getchar 函数时,它会读入一个字符,并返回这个字符。
ch = getchar();
putchar 函数用来写单独一个字符:
putchar(ch);
getchar 和 putchar 会比较快,原因是它们的实现比较简单,并且通常用宏来实现。
sizeof 运算符
运算符 sizeof 允许程序确定用来存储指定类型值所需的空间的大小。
sizeof(类型名)
上述表达式的值是无符号整数,这个整数表示用来存储属于类型名的值所需的字节数。
表达式 sizeof(char) 的值始终为1。
通常情况下, sizeof 运算符也可以应用于常量、变量和表达式。
既然 sizeof 返回的是无符号的整型,所以最安全的做法是把 sizeof 表达式转换成 unsigned long 型。然后用转换说明符 %lu 进行。
Note
或者用%z来输出sizeof的结果。
类型转换
为了让计算机执行算术运算,通常要求操作数有相同的大小(即位的数量相同),并且要求存储的方式也相同。
C语言允许表达式中混合使用基本数据类型,这种情况下编译器可能需要生成一些指令将某些操作数转换成不同类型,使得硬件可以对表达式进行计算。这类转换是隐式转换( implicit conversion )。C语言还允许程序员通过强制运算符执行显式转换( explicit conversion )。
当发生下列情况时会进行隐式转换:
- 当算术表达式或逻辑表达式中操作数类型不同时。
- 当赋值运算符右侧表达式的类型和左侧变量的类型不匹配时。
- 当函数调用中使用的参数类型与其对应的参数类型不匹配时。
- 当 return 语句中表达式的类型和函数返回值的类型不匹配时。
常用的算术转换
常用的算术转换包括算术运算符、关系运算符和判等运算符。
为了统一操作数的类型,通常把相对较狭小的操作数转换成另一个操作数的类型来实现(这就是所谓的提升)。最常用的是整型提升(integral promotion),它把字符或短整数转换成 int 。
两种转换规则:
- 任意操作数是浮点型的情况: float -> double -> long double
- 两个操作数都不是浮点类型: int -> unsigned int -> long int -> unsigned long int
赋值中的转换
C语言遵循一个简单的规则:把赋值运算符右侧的表达式转换成左边变量的类型。把浮点数赋值给整型变量会丢掉小数点后的部分。如果取值在变量的类型范围之外,那么把值赋值给一个较小的类型变量将会得到无意义的结果(甚至更糟)。