四、整数类型
1.简介
整数类型用来表示较大的整数,类型声明使用 int 关键字。
int a;
上面示例声明了一个整数变量 a 。
不同计算机的 int 类型的大小是不一样的。比较常见的是使用4个字节(32位)存储一个 int 类型的值,但是2个字节(16位)或8个字节(64位)也有可能使用。它们可以表示的整数范围如下。
16位:-32,768 到 32,767。
32位:-2,147,483,648 到 2,147,483,647。
64位:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。
2.signed,unsigned
C 语言使用 signed 关键字,表示一个类型带有正负号,包含负值;使用 unsigned 关键字,表示该类型不带有正负号,只能表示零和正整数。对于 int 类型,默认是带有正负号的,也就是说 int 等同于 signed int 。由于这是默认情况,关键字signed 一般都省略不写,但是写了也不算错。
signed int a; // 等同于 int a;
int 类型也可以不带正负号,只表示非负整数。这时就必须使用关键字 unsigned 声明变量。
unsigned int a;
整数变量声明为 unsigned 的好处是,同样长度的内存能够表示的最大整数值,增大了一倍。比如,16位的 signed int 最大值为32,767,而 unsigned int 的最大值增大到了65,535。unsigned int 里面的 int 可以省略,所以上面的变量声明也可以写成下面这样。
unsigned a;
字符类型 char 也可以设置 signed 和 unsigned 。
signed char c; // 范围为 -128 到 127 unsigned char c; // 范围为 0 到 255
注意,C 语言规定 char 类型默认是否带有正负号,由当前系统决定。这就是说, char 不等同于signed char ,它有可能是 signed char ,也有可能是 unsigned char 。这一点与 int 不同, int 就是等同于 signed int 。
3.整数的子类型
如果 int 类型使用4个或8个字节表示一个整数,对于小整数,这样做很浪费空间。另一方面,某些场合需要更大的整数,8个字节还不够。为了解决这些问题,C 语言在 int 类型之外,又提供了三个整数的子类型。这样有利于更精细地限定整数变量的范围,也有利于更好地表达代码的意图。
short int (简写为 short ):占用空间不多于 int ,一般占用2个字节(整数范围为-32768~
32767)。
long int (简写为 long ):占用空间不少于 int ,至少为4个字节。
long long int (简写为 long long ):占用空间多于 long ,至少为8个字节。
short int a; long int b; long long int c;
上面代码分别声明了三种整数子类型的变量。
默认情况下, short 、 long 、 long long 都是带符号的(signed),即 signed 关键字省略了。它们也可以声明为不带符号(unsigned),使得能够表示的最大值扩大一倍。
unsigned short int a; unsigned long int b; unsigned long long int c;
C 语言允许省略 int ,所以变量声明语句也可以写成下面这样。
short a; unsigned short a; long b; unsigned long b; long long c; unsigned long long c;
不同的计算机,数据类型的字节长度是不一样的。确实需要32位整数时,应使用 long 类型而不是 int类型,可以确保不少于4个字节;确实需要64位的整数时,应该使用 long long 类型,可以确保不少于8个字节。另一方面,为了节省空间,只需要16位整数时,应使用 short 类型;需要8位整数时,应该使用 char 类型。
4.整数类型的极限值
有时候需要查看,当前系统不同整数类型的最大值和最小值,C 语言的头文件 limits.h 提供了相应的常量,比如 SCHAR_MIN 代表 signed char 类型的最小值 -128 , SCHAR_MAX 代表 signed char 类型的最大值 127 。
为了代码的可移植性,需要知道某种整数类型的极限值时,应该尽量使用这些常量。
SCHAR_MIN , SCHAR_MAX :signed char 的最小值和最大值。
SHRT_MIN , SHRT_MAX :short 的最小值和最大值。
INT_MIN , INT_MAX :int 的最小值和最大值。
LONG_MIN , LONG_MAX :long 的最小值和最大值。
LLONG_MIN , LLONG_MAX :long long 的最小值和最大值。
UCHAR_MAX :unsigned char 的最大值。
USHRT_MAX :unsigned short 的最大值。
UINT_MAX :unsigned int 的最大值。
ULONG_MAX :unsigned long 的最大值。
ULLONG_MAX :unsigned long long 的最大值。
5.整数的进制
C 语言的整数默认都是十进制数,如果要表示八进制数和十六进制数,必须使用专门的表示法。八进制使用 0 作为前缀,比如 017 、 0377 。
int a = 012; // 八进制,相当于十进制的10
十六进制使用 0x 或 0X 作为前缀,比如 0xf 、 0X10 。
int a = 0x1A2B; // 十六进制,相当于十进制的6699
有些编译器使用 0b 前缀,表示二进制数,但不是标准。
int x = 0b101010;
注意,不同的进制只是整数的书写方法,不会对整数的实际存储方式产生影响。所有整数都是二进制形式存储,跟书写方式无关。不同进制可以混合使用,比如 10 + 015 + 0x20 是一个合法的表达式。
printf() 的进制相关占位符如下。
%d :十进制整数。
%o :八进制整数。
%x :十六进制整数。
%#o :显示前缀 0 的八进制整数。
%#x :显示前缀 0x 的十六进制整数。
%#X :显示前缀 0X 的十六进制整数。
int x = 100; printf("dec = %d\n", x); // 100 printf("octal = %o\n", x); // 144 printf("hex = %x\n", x); // 64 printf("octal = %#o\n", x); // 0144 printf("hex = %#x\n", x); // 0x64 printf("hex = %#X\n", x); // 0X64
6.浮点数类型
任何有小数点的数值,都会被编译器解释为浮点数。所谓“浮点数”就是使用 m * be 的形式,存储一个数值, m 是小数部分, b 是基数(通常是 2 ), e 是指数部分。这种形式是精度和数值范围的一种结合,可以表示非常大或者非常小的数。浮点数的类型声明使用 float 关键字,可以用来声明浮点数变量。
float c = 10.5;
上面示例中,变量 c 的就是浮点数类型。
float 类型占用4个字节(32位),其中8位存放指数的值和符号,剩下24位存放小数的值和符号。float 类型至少能够提供(十进制的)6位有效数字,指数部分的范围为(十进制的) -37 到 37 ,即数值范围为10-37到1037。有时候,32位浮点数提供的精度或者数值范围还不够,C 语言又提供了另外两种更大的浮点数类型。double :占用8个字节(64位),至少提供13位有效数字。long double :通常占用16个字节。注意,由于存在精度限制,浮点数只是一个近似值,它的计算是不精确的,比如 C 语言里面 0.1 + 0.2并不等于 0.3 ,而是有一个很小的误差。
if (0.1 + 0.2 == 0.3) // false
C 语言允许使用科学计数法表示浮点数,使用字母 e 来分隔小数部分和指数部分。
double x = 123.456e+3; // 123.456 x 10^3 // 等同于 double x = 123.456e3;
上面示例中, e 后面如果是加号 + ,加号可以省略。注意,科学计数法里面 e 的前后,不能存在空格。另外,科学计数法的小数部分如果是 0.x 或 x.0 的形式,那么 0 可以省略。
0.3E6 // 等同于 .3E6 3.0E6 // 等同于 3.E6
7.布尔类型
C 语言原来并没有为布尔值单独设置一个类型,而是使用整数 0 表示伪,所有非零值表示真。
int x = 1; if (x) { printf("x is true!\n"); }
上面示例中,变量 x 等于 1 ,C 语言就认为这个值代表真,从而会执行判断体内部的代码。C99 标准添加了类型 _Bool ,表示布尔值。但是,这个类型其实只是整数类型的别名,还是使用 0 表示伪, 1 表示真,下面是一个示例。
_Bool isNormal; isNormal = 1; if (isNormal) printf("Everything is OK.\n");
头文件 stdbool.h 定义了另一个类型别名 bool ,并且定义了 true 代表 1 、 false 代表 0 。只要加载这个头文件,就可以使用这几个关键字。
#include <stdbool.h> bool flag = false;
上面示例中,加载头文件 stdbool.h 以后,就可以使用 bool 定义布尔值类型,以及 false 和 true 表示真伪。
8.字面量的类型
字面量(literal)指的是代码里面直接出现的值。
int x = 123;
上面代码中, x 是变量, 123 就是字面量。编译时,字面量也会写入内存,因此编译器必须为字面量指定数据类型,就像必须为变量指定数据类型一样。一般情况下,十进制整数字面量(比如 123 )会被编译器指定为 int 类型。如果一个数值比较大,超出了 int 能够表示的范围,编译器会将其指定为 long int 。如果数值超过了 long int ,会被指定为unsigned long 。如果还不够大,就指定为 long long 或 unsigned long long 。小数(比如 3.14 )会被指定为 double 类型。
9.字面量后缀
有时候,程序员希望为字面量指定一个不同的类型。比如,编译器将一个整数字面量指定为 int 类型,但是程序员希望将其指定为 long 类型,这时可以为该字面量加上后缀 l 或 L ,编译器就知道要把这个字面量的类型指定为 long 。
int x = 123L;
上面代码中,字面量 123 有后缀 L ,编译器就会将其指定为 long 类型。这里 123L 写成 123l ,效果也是一样的,但是建议优先使用 L ,因为小写的 l 容易跟数字 1 混淆。八进制和十六进制的值,也可以使用后缀 l 和 L 指定为 Long 类型,比如 020L 和 0x20L 。
int y = 0377L; int z = 0x7fffL;
如果希望指定为无符号整数 unsigned int ,可以使用后缀 u 或 U 。
int x = 123U;
L 和 U 可以结合使用,表示 unsigned long 类型。 L 和 U 的大小写和组合顺序无所谓。
int x = 123LU;
对于浮点数,编译器默认指定为 double 类型,如果希望指定为其他类型,需要在小数后面添加后缀f (float)或 l (long double)。
科学计数法也可以使用后缀。 1.2345e+10F 1.2345e+10L
总结一下,常用的字面量后缀有下面这些。
f 和 F : float 类型。
l 和 L :对于整数是 long int 类型,对于小数是 long double 类型。
ll 和 LL :Long Long 类型,比如 3LL 。
u 和 U :表示 unsigned int ,比如 15U 、 0377U 。
u 还可以与其他整数后缀结合,放在前面或后面都可以,比如 10UL 、 10ULL 和 10LLU 都是合法的。
下面是一些示例。
int x = 1234; long int x = 1234L; long long int x = 1234LL unsigned int x = 1234U; unsigned long int x = 1234UL; unsigned long long int x = 1234ULL; float x = 3.14f; double x = 3.14; long double x = 3.14L;