C 变量、常量与字面量
更新时间:2026-08-26。本文是
languages/c/主题入门层第 4 篇。程序没有数据就是空壳,这一篇讲数据的第一课:变量怎么声明、常量怎么定义、3和3.14这种"裸写的数字"到底什么类型。都是细节,但细节决定你后面会不会被类型坑到。
本文要回答的问题
int x;和int x = 0;有什么区别?变量会"自带"一个值吗?- 常量有两种写法:
const和#define,该用哪个? - 数字字面量
3、3.14、3L各是什么类型?
一、声明、定义与初始化
int x; // 声明 + 定义:给 x 分配空间,但还没给值
int y = 42; // 声明 + 定义 + 初始化:一步到位C 里"声明"(告诉编译器有这个变量)和"定义"(真的分配空间)常常是一起的,入门阶段先不用抠这个区分。真正重要的是:
局部变量未初始化,值是"垃圾"——它指向栈上那段内存残留的旧数据:
int main(void) {
int x;
printf("%d\n", x); // 输出啥?不确定!可能是 0,可能是 32767,可能是负数
return 0;
}这不是随机数,是"上一次使用这块内存的程序留下的痕迹"。编译时加 -Wall 会警告 x is used uninitialized,但这只对直接使用的情况有效,指针传出去后编译器就管不到了。规则很简单:声明时顺手初始化,写 int x = 0; 比写 int x; 多敲不了几个字符,却能少一大类 bug。
二、命名规则
| 规则 | 说明 | 示例 |
|---|---|---|
| 只能字母、数字、下划线 | 不能有空格、-、. | user_count 可以,user-count 不行 |
| 不能以数字开头 | — | 1st 不行 |
| 不能是关键字 | 见下 | int、return 不能当名字 |
| 大小写敏感 | count 和 Count 是两个变量 | — |
C 的关键字(int、char、return、if、for、sizeof……)是保留的,不能用作变量名。命名风格上,C 社区惯例是小写下划线(snake_case):total_count、file_name。全大写是 #define 常量的惯例,见下节。
三、常量:const 还是 #define
const int MAX_SIZE = 100; // const 常量:有类型、有作用域
#define MAX_SIZE 100 // 宏常量:预处理期直接文本替换| 维度 | const int | #define |
|---|---|---|
| 处理时机 | 编译期 | 预处理期(文本替换) |
| 有类型 | 有(int) | 无,纯文本 |
| 报错信息 | 类型不匹配会报错 | 不报,替换后编译错误莫名其妙 |
| 作用域 | 和变量一样 | 从定义处到文件尾,无块作用域 |
现代 C 推荐 const。#define 文本替换的坑很经典:
#define SQUARE(x) x * x
int a = SQUARE(3 + 1); // 展开成 3 + 1 * 3 + 1 = 7,而不是 16!#define 适合的场景是编译期开关(如 #define DEBUG)和少数无法用 const 表达的场景,函数宏的正确写法在预处理、宏与调试里讲。写普通常量用 const。
四、字面量:裸写的数字也是有类型的
int a = 3; // 3 是 int
long b = 3L; // L 后缀:3L 是 long
unsigned c = 3U; // U 后缀:unsigned
float d = 3.14f; // f 后缀:3.14f 是 float
double e = 3.14; // 没有后缀的小数默认是 double| 写法 | 类型 |
|---|---|
3 | int |
3L / 3l | long |
3LL | long long |
3U / 3u | unsigned int |
3UL | unsigned long |
3.14 | double |
3.14f | float |
'A' | char(字符常量) |
数值过大时后缀就派上用场了:10000000000 超出 int 范围,写成 10000000000L 才安全。printf 里 %ld 配 long、%f 配 double、%zu 配 size_t,格式和类型不匹配是 UB(未定义行为)——不报错,但可能打出离谱的数。这个坑在 printf 格式化输出 里重点讲。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 未初始化就用 | 输出神秘数值 | 声明即初始化 |
| 命名撞关键字 | 编译直接报错 | 避开 int/return 等 |
#define 无括号 | 展开后算错 | 用 const,宏加括号 |
| 类型后缀缺失 | %ld 配 int 打出错值 | 大数记得加 L/LL |
| 变量名与宏同名 | 宏替换把代码改坏 | 宏名全大写 |
六、与本站主线衔接
- 变量在内存里怎么排布(栈、寄存器、生命周期),见作用域与生命周期;
int到底占几个字节、size_t为什么是%zu,见基本数据类型(下一篇);- 未定义行为(UB)的完整解释,见专家层未定义行为与优化。
一句话总结
变量声明时就初始化、命名用 snake_case、常量优先 const 而非 #define、字面量看后缀辨类型——四句话记住,后面的类型课和指针课会少踩一半的坑。
上一篇:程序结构与 main 函数 下一篇:基本数据类型