Skip to content

数据类型(Data Types)

数据类型决定了变量"能存什么值"以及"占多少内存"。选择正确的类型是编写正确、高效代码的第一步。


1. 为什么需要数据类型

计算机中所有数据最终都是 0 和 1。数据类型告诉编译器:

  • 占多大空间int 通常占 4 字节,char 占 1 字节。
  • 如何解释:同一段二进制,当作 int 是整数,当作 float 是小数。
  • 允许什么操作int 可以做取模(%),float 不能直接取模。
内存中的同一段二进制 01000000 01001000 11110101 11000011:

解释为 int    →  1078523331
解释为 float  →  3.14
解释为 char[4] → '@' 'H' '?' '?'

2. 基本数据类型一览

类型 关键字 典型大小 取值范围 用途
字符型 char 1 字节 -128 ~ 127 或 0 ~ 255 存储 ASCII 字符
短整型 short 2 字节 -32768 ~ 32767 小范围整数
整型 int 4 字节 -2,147,483,648 ~ 2,147,483,647 常规整数
长整型 long 4 或 8 字节 平台相关 较大范围整数
长长整型 long long 8 字节 ±9.22×10¹⁸ 极大整数
单精度浮点 float 4 字节 ±3.4×10³⁸,6~7 位有效数字 普通小数
双精度浮点 double 8 字节 ±1.7×10³⁰⁸,15~16 位有效数字 高精度小数
无类型 void 表示"无返回值"或"无参数"

注意intlong 的具体大小取决于编译器和平台。可用 sizeof 运算符查看实际大小。


3. 深入理解各类型

3.1 整数类型(Integer Types)

char   c  = 'A';         // 字符本质是小整数,'A' 的 ASCII 值是 65
short  s  = 32767;       // 适合小范围计数
int    i  = 42;          // 默认的整数类型,日常首选
long   l  = 100000L;     // 后缀 L 表示 long 字面量
long long ll = 9000000000LL; // 后缀 LL 表示 long long

无符号(unsigned)变体:将符号位也用来表示数值,范围扩大一倍但只能表示非负数。

类型 有符号范围 无符号范围
char / unsigned char -128 ~ 127 0 ~ 255
int / unsigned int ±21 亿 0 ~ 42 亿
short / unsigned short ±32767 0 ~ 65535
unsigned int count = 100;    // 明确表示"计数"——不可能是负数
unsigned char byte = 0xFF;   // 表示一个原始字节,用于底层操作

3.2 浮点类型(Floating-Point Types)

浮点数用科学计数法的二进制形式存储,因此存在精度限制。

float  f = 3.1415926535f;   // 后缀 f 表示 float 字面量
double d = 3.1415926535;    // 默认的小数字面量是 double 类型

精度差异示例

float  a = 1.0f / 3.0f;     // 0.3333333(约 7 位有效数字)
double b = 1.0 / 3.0;       // 0.3333333333333333(约 15 位有效数字)

浮点数不能精确表示所有十进制小数(如 0.1 在二进制中是无限循环小数),因此不要用 == 直接比较两个浮点数是否相等

float x = 0.1f + 0.2f;
if (x == 0.3f) {  // 可能为假!
    // 不可靠
}

// 正确做法:判断差值是否在可接受范围内
float epsilon = 0.000001f;
if (fabs(x - 0.3f) < epsilon) {
    // 认为近似相等
}

3.3 字符类型(char

char 本质上是一个 1 字节的整数,ASCII 字符只是它的"人类可读"形式。

char ch1 = 'A';         // ch1 的实际值是 65
char ch2 = 65;          // 等价于 'A',但不推荐这样写

printf("%c\n", ch1);    // 输出:A
printf("%d\n", ch1);    // 输出:65
转义字符 含义
\n 换行
\t 制表符(Tab)
\\ 反斜杠本身
\' 单引号
\" 双引号
\0 空字符(字符串结束标志)

3.4 void 类型

void 表示"没有类型",主要用于三种场景:

void func() { ... }              // 函数不返回任何值
int rand(void) { ... }           // 函数不接受任何参数(显式声明)
void* ptr = malloc(100);         // 通用指针,可指向任意类型

4. 用 sizeof 查看类型大小

printf("char      : %zu 字节\n", sizeof(char));
printf("short     : %zu 字节\n", sizeof(short));
printf("int       : %zu 字节\n", sizeof(int));
printf("long      : %zu 字节\n", sizeof(long));
printf("long long : %zu 字节\n", sizeof(long long));
printf("float     : %zu 字节\n", sizeof(float));
printf("double    : %zu 字节\n", sizeof(double));

在典型 64 位系统上的输出:

char      : 1 字节
short     : 2 字节
int       : 4 字节
long      : 8 字节(Windows 上为 4 字节)
long long : 8 字节
float     : 4 字节
double    : 8 字节

5. 类型选择指南

面对一个具体需求时,按以下优先级选择类型:

场景 推荐类型 原因
常规计数、索引、年龄 int 范围足够大,处理速度最快,是天然字长
明确非负的计数 unsigned int 语义清晰,范围大一倍
嵌入式/内存敏感的计数器 unsigned charunsigned short 节省内存
科学计算、工程数值 double 精度高,现代 CPU 对 double 运算也有硬件加速
图形学/游戏中的颜色、坐标 float 精度足够且内存占用是 double 的一半
ASCII 字符 char 1 字节,语义明确
文件大小、极大数值 long long 8 字节,范围足够
时间戳(秒) time_t(通常是 long 使用标准库类型保证兼容性

决策流程图

需要存什么?
  ├── 整数
  │     ├── 范围 ≤ 255 且非负 → unsigned char
  │     ├── 范围 ≤ 65535 且非负 → unsigned short
  │     ├── 范围 ≤ 21 亿 → int
  │     ├── 明确非负、范围 ≤ 42 亿 → unsigned int
  │     └── 超出以上 → long long
  │
  ├── 小数
  │     ├── 内存紧张、精度要求不高 → float
  │     └── 默认选择 → double
  │
  ├── 单个字符 → char
  │
  └── 无返回值/通用指针 → void

6. 类型转换(Type Casting)

隐式转换(自动)

当不同类型混合运算时,编译器自动将"窄"类型提升为"宽"类型:

int    a = 10;
double b = 3.14;
double c = a + b;     // a 被自动转换为 double,结果为 13.14

int    d = a + b;     // 13.14 被截断为 13(小数部分丢失)

显式转换(手动指定)

int   x = 10, y = 3;
float result = (float)x / y;   // 将 x 转为 float,得到 3.333333
// 如果不转换:10 / 3 = 3(整数除法截断)

类型提升规则

char / short  →  int  →  unsigned int  →  long  →  unsigned long
                                              ↘  float  →  double  →  long double

7. 总结

要点 说明
默认整数用 int 范围足够,速度最快
默认小数用 double 精度高,现代硬件支持好
float 有精度限制 不可直接 == 比较
sizeof 查看大小 不同平台结果可能不同
整数除法会截断 需要小数结果时先转换为浮点类型
无符号类型无负数 选择时确认语义是否需要负值

作者: Qing | 修改日期: 2026-07-18