const 关键字
const 是 "constant" 的缩写,意为“常量”,它的核心作用是告诉编译器,一个变量的值在初始化后不能被修改。

(图片来源网络,侵删)
const 的基本用法
-
修饰普通变量
const int a = 10; // a = 20; // 错误!编译器会报错,不能给 const 变量赋值
这里,
a被声明为一个常量,任何试图修改a的行为都会在编译阶段被捕获并报错。 -
修饰指针
const修饰指针时有两种情况,这也是一个常见的考点:- *
const在 `` 左边:指针指向的内容是常量,不能通过指针修改。**const int *ptr1 = &a; // 或者 int const *ptr1 = &a; *ptr1 = 20; // 错误!不能通过 ptr1 修改它指向的内容 ptr1 = &b; // 正确!可以改变指针的指向,让它指向另一个变量
- *
const在 `` 右边:指针本身是常量,指针的指向不能改变。**int * const ptr2 = &a; *ptr2 = 20; // 正确!可以通过 ptr2 修改它指向的内容 ptr2 = &b; // 错误!不能改变指针的指向
- *
const在 `` 两边:指针本身和它指向的内容都是常量。**const int * const ptr3 = &a; *ptr3 = 20; // 错误! ptr3 = &b; // 错误!
- *
const 的主要作用
- 提高代码健壮性:防止意外地修改不应该被修改的变量,减少 bug。
- 增加代码可读性:看到
const,其他开发者就能立刻明白这个变量的意图是“只读”的。 - 为编译器优化提供信息:编译器知道变量的值不会变,可以进行一些优化,比如将常量值直接内联到代码中,而不是从内存读取。
static 关键字
static 关键字的含义会根据其作用域的不同而改变,主要有三种用法:

(图片来源网络,侵删)
1. 修饰全局变量(在函数外部)
当一个全局变量被 static 修饰时,它的链接属性从 外部链接 变为 内部链接。
- 全局变量(不带
static):具有外部链接,它的作用域是整个程序(从定义点到文件末尾),可以被同一个程序的其他源文件(通过extern声明)访问。 static全局变量:具有内部链接,它的作用域被限制在当前源文件内部,其他文件即使使用extern也无法访问它。
示例:
file1.c
#include <stdio.h>
// 这是一个全局变量,具有外部链接
int global_var = 1;
// 这是一个 static 全局变量,具有内部链接
static int static_global_var = 2;
void print_from_file1() {
printf("In file1: global_var = %d\n", global_var);
printf("In file1: static_global_var = %d\n", static_global_var);
}
file2.c

(图片来源网络,侵删)
#include <stdio.h>
extern int global_var; // 可以访问 file1.c 中的 global_var
// extern int static_global_var; // 错误!无法访问 file1.c 中的 static_global_var
void print_from_file2() {
printf("In file2: global_var = %d\n", global_var);
// printf("In file2: static_global_var = %d\n", static_global_var); // 编译错误
}
static 修饰全局变量,是为了实现信息隐藏,避免全局变量污染命名空间,防止被其他文件意外修改。
2. 修饰局部变量(在函数内部)
当一个局部变量被 static 修饰时,它会发生两个变化:
- 生命周期改变:它的生命周期不再是随着函数的调用和结束而创建和销毁,而是变成了整个程序的运行周期,它只被初始化一次。
- 存储位置改变:它不再存储在栈上,而是存储在静态存储区(全局/静态区)。
- 作用域不变:它的作用域仍然仅限于定义它的函数内部。
示例:
#include <stdio.h>
void counter() {
// 普通局部变量
int local_count = 0;
local_count++;
printf("Local count: %d\n", local_count);
// static 局部变量
static int static_count = 0; // 只在第一次调用时初始化为 0
static_count++;
printf("Static count: %d\n", static_count);
}
int main() {
counter(); // Local count: 1, Static count: 1
counter(); // Local count: 1, Static count: 2
counter(); // Local count: 1, Static count: 3
return 0;
}
static 修饰局部变量,是为了实现函数状态的保持,让函数拥有“记忆”功能。
3. 修饰函数
static 修饰函数的效果与修饰全局变量类似,将函数的链接属性从外部链接变为内部链接。
- 普通函数:可以被其他源文件调用。
static函数:只能在当前源文件内部被调用,不能被其他文件通过函数名调用。
示例:
utils.c
#include <stdio.h>
// 这是一个 static 函数,只能在 utils.c 内部使用
static void helper_function() {
printf("This is a helper function.\n");
}
// 这是一个公共函数,可以被其他文件调用
void public_function() {
helper_function();
}
main.c
#include <stdio.h>
extern void public_function();
// extern void helper_function(); // 错误!无法调用
int main() {
public_function(); // 正确
// helper_function(); // 编译错误
return 0;
}
static 修饰函数,同样是实现信息隐藏,将工具函数限制在文件内部,避免命名冲突。
static const 组合使用
当 static 和 const 组合在一起时,它们的作用是相加的,非常强大且常用。
1. static const 修饰全局变量
这是最常见、最推荐的用法之一,它创建了一个具有文件作用域的、只读的常量。
// file1.c static const int MAX_SIZE = 1024;
这行代码的含义是:
const:MAX_SIZE是一个常量,不能被修改。static:MAX_SIZE的链接属性是内部的,只能在file1.c中使用。
为什么比 #define 更好?
- 类型安全:
const变量有明确的类型(如int,float),而#define只是简单的文本替换,没有类型概念。 - 有作用域:
static const变量遵循 C 语言的变量作用域规则,而#define不受作用域限制,可能导致命名冲突。 - 调试友好:
const变量在符号表中存在,调试器可以查看它的值,而#define在预处理阶段就被替换掉了,调试时看不到。
对比 #define:
// 方法1: #define (不推荐用于复杂值,但简单宏依然有用途) #define PI 3.14159 // 方法2: static const (推荐) static const double PI = 3.14159;
2. static const 修饰局部变量
void some_function() {
static const int cache_size = 100; // 初始化一次,且值不能改变
// ... 使用 cache_size ...
}
这种情况较少见,因为 const 本身已经保证了值不被修改,而 static 的“记忆”功能在这里意义不大,通常如果需要一个不变的值,直接用 const 局部变量即可。
总结与最佳实践
| 关键字组合 | 修饰对象 | 作用域 | 生命周期 | 链接属性 | 主要用途 |
|---|---|---|---|---|---|
const |
全局/局部 | 文件/函数 | 整个程序 | 外部/内部 | 定义只读变量,增强安全性 |
static |
全局 | 文件 | 整个程序 | 内部 | 信息隐藏,限制变量/函数作用域 |
static |
局部 | 函数 | 整个程序 | 无(内部) | 保持函数状态,变量只初始化一次 |
static const |
全局 | 文件 | 整个程序 | 内部 | 定义文件级的命名常量(推荐) |
static const |
局部 | 函数 | 整个程序 | 无 | 定义函数内不变的值(较少用) |
核心要点:
const约束的是可读性(变量值不能改)。static约束的是可见性(作用域和链接属性)。static const是 C 语言中定义文件级私有常量的黄金标准,它结合了const的类型安全和static的信息隐藏,是比#define更现代、更安全的选择。
理解 static 和 const 的区别与联系,是写出高质量、可维护、无 bug 的 C 代码的重要一步。
