C 语言的数据类型有很多,可以分为 4 大类型:
- void 类型
- 基本类型
- 字符类型
- 有符号整数类型
- 无符号整数类型
- 浮点类型
- 枚举类型
- 派生类型
- 数组类型
- 结构体类型
- 联合体类型(也叫共同体类型)
- 函数类型
- 指针类型
一、基本类型
有符号整数类型
char
(等价类型:signed char
)short
(等价类型:signed short
、short int
、signed short int
)int
(等价类型:signed int
、signed
)long
(等价类型:signed long
、long int
、signed long int
)(C99 起)long long
(等价类型:signed long long
、long long int
、signed long long in
t`)(C99 起)
无符号整数类型
- unsigned char
- unsigned short(等价类型:
unsigned short int
) - unsigned int(等价类型:
unsigned
) - unsigned long(等价类型:
unsigned long int
)(C99 起) - unsigned long long(等价类型:
unsigned long long int
)(C99 起)
字符类型
char
浮点类型
float
double
long double
1.1. 整数类型
1.1.1. 整数类型大小
C 标准规定
1 | 1 == sizeof(char) |
1.1.2. 数据模型
关于基本类型大小的是实现方案,统称为:数据模型。有 4 种常见的数据模型
32bit 系统(指针为 32 位)
- LP32
- Win16 API
- ILP32
- Win32 API
- Unix、类 Unix 系统(Linux、Mac OS X)
- LP32
64bit 系统(指针为 64 位)
- LLP64
- Win64 API
- LP64
- Unix、类 Unix 系统(Linux、Mac OS X)
- LLP64
比较少见的数据模型
- ILP64:int、long、指针均为 64 位
- 仅出现在早期 64 位 Unix 系统(例如 Unicos on Cray)
- ILP64:int、long、指针均为 64 位
1.1.3. 有符号整数类型和无符号整数类型区别
整数类型可分为:有符号整数类型、无符号整数类型。
1.1.4. 有符号整数 char、无符号整数 unsigned char
1 | // 0xBD <=> 0b10111101 |
1 | // 0x43 <=> 0b01000011 |
- c1、c2 变量在内存中存放的二进制数据是完全一样的;
- 对于同一份二进制数据,分别以有符号数形式、无符号数形式解读出来的含义可能是不一样的。
1.1.5. 整数的取值范围
char
、unsigned char
都只占用一个字节,能够存放的二进制数据范围都是[0b0000 0000, 0b1111 1111]
。
char
的取值范围:$[-128, 127] = [-2^7, 2^7-1]$unsigned char
的取值范围:$[0, 255] = [0, 2^8-1]$- 有 n 个二进制位的有符号数的取值范围$[-2^{n-1}, 2^{n-1}-1]$
- 有 n 个二进制位的无符号数的取值范围$[0, 2^n-1]$
位数 | 符号 | 最小值 | 最大值 |
---|---|---|---|
8 | 有符号 | $$-2^7(128)$$ | $$2^7-1(127)$$ |
8 | 无符号 | 0 | $$2^8-1(255)$$ |
16 | 有符号 | $$-2^{15}(-32768)$$ | $$2^{15}-1(32767)$$ |
16 | 无符号 | 0 | $$2^{16}-1(65535)$$ |
32 | 有符号 | $$-2^{31}(-2147483648)$$ | $$2^{31}-1(2147483647)$$ |
32 | 无符号 | 0 | $$2^{32}-1(4294967295)$$ |
64 | 有符号 | $$-2^{63}(-922337203685477808)$$ | $$2^{63}-1(922337203685477807)$$ |
64 | 无符号 | 0 | $$2^{64}-1(18446744073709551615)$$ |
1.1.6. 溢出(Overflow)
溢出指的是内容超过了已知容器的容量。
例:short s;
short
类型的变量 s 有 2 个字节的内存空间- 如果要将超过 2 个字节(比如 4 个字节)的数据存储到变量 s 中去,就会产生内存溢出
案例一:
1 | int i = 16909292; |
- 当出现溢出时,会优先保留低字节的数据,舍弃高字节的数据;
- 所以在给取值范围小的变量赋值时要注意防止数据溢出,否则结果可能会跟预期不符合。
思考:那是不是以后都统一使用取值范围比较大的变量就好了?
应该根据已知的数据范围选择合适大小的变量,不然会造成内存空间的浪费
案例二:
1 | int i = 16909292; |
案例三:
1 | unsigned char c1 = 255; |
1 | c1 = c1 + 1; |
案例四:
1 | unsigned char c1 = 0; |
1 | c1 = c1 - 1; |
案例五:
1 | unsigned char c1 = 127; |
1 | c1 = c1 + 1; |
案例六:
1 | unsigned char c1 = 128; |
1 | c1 = c1 - 1; |
案例七:
1 | unsigned char c1 = 255; |
1 | c1 = c1 + 1; |
案例八:
1 | unsigned char c1 = 0; |
1 | c1 = c1 - 1; |
1.1.7. unsigned char、char 的取值范围
1.2. 浮点类型
浮点类型可以用来表示小数(比如 3.14),包括float
,double
,long double
类型
最常用的浮点类型是float
和double
,一般在数值后面加上 f 或者 F 表示十 float 类型的数值
1 | float f = 3.14F; |
float
:单精度(Single)浮点类型,占用 32bit,可以保证精确到小数点后 6 位- 最小值:$$-3.4*10^{38}$$
- 最大值:$$3.4*10^{38}$$
double
:双精度(Double)浮点类型,占用 64bit,可以保证精确到小数点后 15 位- 最小值:$$-1.8*10^{308}$$
- 最大值:$$1.8*10^{308}$$
1.2.1. 浮点类型的存储细节
思考:为什么 32bit 的
unsigned int
最大值是 2^32-1,而 32bit 的float
最大值是 3.4 * 10^38?
因为他们的存储方式不一样,浮点数在计算机中是按照 IEEE 754 标准存储的。
1.3. 整数、浮点数字面量
1 | char c = 10; |
1.4. printf 中的转换格式指定符
1.4.1. 案例一
1 | printf("%zd\n", sizeof(int)); // 输出:4 |
1.4.2. 案例二
1 | // 用%%来显示一个% |
1.5. scanf 中的转换格式指定符
1 | // 用%%来匹配一个% |
1.6. 类型转换
格式:
1 | 类型1 v1 = xx; |
案例:
1 | char c = 'A'; |
其实在很多时候,编译器都会进行隐式类型转换:
1 | char c = 'A'; |
大类型转小类型的时候,可能会丢失精度:
1 | double d = 3.14; |