C语言从入门到进阶——第2讲:C语言数据类型和变量
这一讲是C语言最基础但也最容易埋坑的部分。
数据类型决定了你能存什么、占多少内存、能表示的范围,以及后续运算的规则。很多初学者在这一步没打好基础,后面的指针、数组、函数传参、内存对齐等问题都会反复踩坑。
1. C语言的基本数据类型一览(2025–2026主流64位系统)
| 类型关键字 | 常见字节数 | 典型取值范围(64位系统) | 默认对齐 | 默认值(全局/静态变量) | 常见包装/别名(C99+) | 备注 / 最常用场景 |
|---|---|---|---|---|---|---|
| char | 1 | -128 ~ 127 或 0 ~ 255 | 1 | 0 | — | 字符、字节、小整数 |
| signed char | 1 | -128 ~ 127 | 1 | 0 | — | 明确要负数的小整数 |
| unsigned char | 1 | 0 ~ 255 | 1 | 0 | uint8_t / byte | 字节流、网络数据、位操作 |
| short | 2 | -32,768 ~ 32,767 | 2 | 0 | int16_t | 节省内存的整数(较少单独用) |
| unsigned short | 2 | 0 ~ 65,535 | 2 | 0 | uint16_t | — |
| int | 4 | -2,147,483,648 ~ 2,147,483,647 | 4 | 0 | int32_t | 最常用整数类型 |
| unsigned int | 4 | 0 ~ 4,294,967,295 | 4 | 0 | uint32_t | 位运算、计数器 |
| long | 8(LP64) | -9.2e18 ~ 9.2e18 | 8 | 0L | long int | — |
| unsigned long | 8 | 0 ~ 1.84e19 | 8 | 0UL | — | — |
| long long | 8 | -9.2e18 ~ 9.2e18 | 8 | 0LL | int64_t | 大整数、时间戳、文件大小 |
| unsigned long long | 8 | 0 ~ 1.84e19 | 8 | 0ULL | uint64_t | 现代C最常用64位无符号整数 |
| float | 4 | ≈ ±3.4e38(6–7位有效数字) | 4 | 0.0f | — | 图形、科学计算(精度较低) |
| double | 8 | ≈ ±1.8e308(15–16位有效数字) | 8 | 0.0 | — | 浮点数默认首选 |
| long double | 12/16 | 平台相关(x86常见80位扩展精度) | 平台相关 | 0.0L | — | 高精度计算(不跨平台) |
| _Bool | 1 | 0 或 1 | 1 | 0 | bool(stdbool.h) | C99引入,逻辑值 |
最重要记忆口诀(2025–2026主流环境):
- char → 1 字节
- short → 2 字节
- int → 4 字节
- long long → 8 字节
- float → 4 字节(单精度)
- double → 8 字节(双精度,默认浮点字面量类型)
2. 变量声明与定义的写法对比
// 仅声明(告诉编译器有这个名字,后面会定义)
extern int global_count;
// 定义并初始化(分配内存)
int a = 10; // 定义 + 初始化
int b; // 定义(自动初始化为0 —— 全局/静态变量)
static int c = 0; // 静态变量,文件作用域,初始化为0
// 同时声明和定义(最常见)
int main(void) {
int x = 42; // 局部变量,未初始化 → 随机值(未定义行为!)
static int y = 100; // 静态局部变量,只初始化一次
const int z = 200; // 常量,必须初始化
return 0;
}
最容易犯的错误 Top 5(新手必踩):
- 局部变量不初始化就使用 → 未定义行为(可能是随机值、崩溃)
- 把
int a = 1, b = 2, c;写成一行,最后一个没初始化 - 误以为
char c = 'A';占 1 字节,实际上字符串"A"占 2 字节(含\0) - 字面量默认类型没搞清楚:
3.14→ double3.14f→ float10000000000→ int(溢出!)→ 必须写10000000000LL
- signed 和 unsigned 混用导致隐式转换问题
3. 类型转换与溢出(最常考点)
隐式转换优先级(从小到大):
char / signed char / unsigned char
↓
short / unsigned short
↓
int / unsigned int
↓
long / unsigned long
↓
long long / unsigned long long
↓
float → double → long double
经典溢出例子(面试/调试必考):
unsigned int a = 0xFFFFFFFF; // 4294967295
printf("%u\n", a + 1); // 输出 0(无符号环绕)
int b = 0x7FFFFFFF; // 2147483647
printf("%d\n", b + 1); // 未定义行为(通常 -2147483648)
4. sizeof 与对齐(进阶必知)
#include <stdio.h>
int main() {
printf("char : %zu\n", sizeof(char)); // 1
printf("int : %zu\n", sizeof(int)); // 4
printf("double : %zu\n", sizeof(double)); // 8
printf("long long: %zu\n", sizeof(long long)); // 8
struct Test {
char a; // 1
int b; // 4,但因为对齐,前面补3字节
double c; // 8
} t;
printf("struct Test size: %zu\n", sizeof(t)); // 通常 16(对齐到最大成员double的8字节)
return 0;
}
对齐规则快速记忆:
- 每个成员的起始地址 = 自身大小的整数倍
- 整个结构体大小 = 最大成员对齐数的整数倍
5. 这一讲核心总结口诀(背下来)
- char 1、short 2、int 4、long long 8、double 8
- 局部变量不初始化 = 垃圾值,千万别直接用
- 字面量:整数默认int,浮点默认double,加后缀改变(f、LL、U)
- unsigned 溢出环绕,signed 溢出未定义行为
- sizeof 是运算符,不是函数;结果是 size_t(无符号)
- 现代C强烈建议用 的定宽类型:int32_t、uint64_t、int64_t 等
下一讲预告:常量、运算符、表达式、常见隐式转换陷阱、枚举与 typedef
有想重点深挖的部分吗?
比如:
- float/double 在内存中的 IEEE 754 表示
- signed → unsigned 转换的具体规则
- 结构体/联合体/位域的对齐细节
- 各种整数字面量写法导致的溢出案例
随时告诉我,我继续展开。