C语言中const的详细用法
C语言中const关键字的深度解析
const是C语言中用于定义常量的关键字,它使变量成为只读状态,防止程序意外修改重要数据。正确使用const能显著提高代码的健壮性、可读性和安全性。
一、基础用法:定义常量
1. 基本常量定义
const int MAX_SIZE = 100; // 整型常量
const float PI = 3.14159; // 浮点常量
const char NEWLINE = '\n'; // 字符常量
2. 常量与宏定义的区别
| 特性 | const常量 |
#define宏 |
|---|---|---|
| 类型检查 | 有 | 无(预处理器替换) |
| 作用域 | 块作用域 | 文件作用域 |
| 调试可见性 | 调试器中可见 | 预编译后消失 |
| 内存分配 | 占用内存空间 | 不占用内存 |
| 数组大小定义 | C99前不能用于数组大小 | 可用于数组大小 |
// const定义(C99前不合法,C99后合法)
const int SIZE = 10;
int arr[SIZE]; // C99前错误,C99后正确
// 宏定义(始终合法)
#define SIZE 10
int arr[SIZE]; // 始终正确
二、高级用法:指针与const
const与指针结合使用有4种组合方式,每种都有不同的保护级别:
1. 指向常量的指针(Pointer to constant)
int value = 10;
const int *ptr = &value; // ptr指向的内容不可变
// *ptr = 20; // 错误:不能通过ptr修改value
value = 20; // 正确:value本身不是常量
ptr = NULL; // 正确:指针本身可变
2. 常量指针(Constant pointer)
int a = 5, b = 10;
int *const ptr = &a; // ptr本身不可变
*ptr = 15; // 正确:可以修改指向的值
// ptr = &b; // 错误:不能改变指针指向
3. 指向常量的常量指针(Constant pointer to constant)
const int value = 100;
const int *const ptr = &value; // 指针和内容都不可变
// *ptr = 200; // 错误:不能修改内容
// ptr = NULL; // 错误:不能修改指针
4. 常量指针指向变量(较少用)
int data = 42;
int *const ptr = &data; // 指针不变,内容可变
*ptr = 99; // 正确
// ptr = &data2; // 错误
三、const在函数中的应用
1. 保护函数参数
// 保护原始数据不被修改
void print_string(const char *str) {
// str[0] = 'A'; // 错误:不能修改
printf("%s\n", str);
}
// 保护指针不被修改
void init_array(int *const arr, int size) {
// arr = NULL; // 错误:不能修改指针
for(int i=0; i<size; i++) {
arr[i] = 0;
}
}
2. 返回const指针
// 返回指向常量的指针
const char *get_error_message(int code) {
static const char *messages[] = {
"Success",
"Invalid input",
"Out of memory"
};
return messages[code];
}
// 使用
const char *msg = get_error_message(1);
// msg[0] = 'X'; // 错误:不能修改
四、const与复合数据类型
1. 结构体中的const
struct Point {
int x;
int y;
};
// 整个结构体为常量
const struct Point origin = {0, 0};
// origin.x = 1; // 错误
// 结构体成员为常量
struct ImmutablePoint {
const int x;
const int y;
};
struct ImmutablePoint p = {10, 20};
// p.x = 30; // 错误
2. 数组中的const
// 常量数组
const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
// days[1] = 29; // 错误
// 指向常量数组的指针
const char *const months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
// months[0] = "January"; // 错误
// months = NULL; // 错误
五、const的底层机制
1. 存储位置
- 全局const变量:通常存储在只读数据段(.rodata)
- 局部const变量:存储在栈上,但编译器阻止修改
- 动态分配的const:存储在堆上,但语义上只读
2. 强制修改(危险操作)
const int immutable = 100;
int *ptr = (int*)&immutable; // 强制转换去除const
*ptr = 200; // 未定义行为!可能崩溃或无效修改
printf("%d vs %d\n", immutable, *ptr);
// 可能输出:100 vs 200(编译器优化导致)
六、最佳实践与常见陷阱
1. 最佳实践
// 1. 函数参数:指针参数应加const保护
size_t strlen(const char *s);
// 2. 硬件寄存器映射
volatile const uint32_t *HW_REGISTER = (uint32_t*)0xFFFF0000;
// 3. 跨文件共享常量(头文件中)
// config.h
extern const int MAX_USERS;
// config.c
const int MAX_USERS = 1000;
2. 常见错误
// 错误1:忘记初始化
const int MIN_VALUE; // 错误:未初始化常量
// 错误2:修改const指针内容
const int arr[] = {1,2,3};
int *p = arr; // 警告:丢弃const限定符
*p = 4; // 运行时错误(写入只读内存)
// 错误3:返回局部const指针
const char *get_name() {
const char name[] = "Alice"; // 局部数组
return name; // 返回悬垂指针!
}
七、const在嵌入式开发中的特殊应用
1. 只读硬件寄存器
// 定义只读硬件寄存器
#define HW_VERSION (*(volatile const uint32_t *)0x400FE000)
void print_version() {
printf("Hardware Version: 0x%08X\n", HW_VERSION);
}
2. 配置表保护
// 存储在Flash中的配置表
const struct {
uint16_t baud_rate;
uint8_t parity;
uint8_t stop_bits;
} UART_CONFIG = {115200, 0, 1};
// 防止意外修改
void init_uart() {
setup_uart(UART_CONFIG.baud_rate,
UART_CONFIG.parity,
UART_CONFIG.stop_bits);
}
八、const与类型限定符组合
1. const + volatile
// 只读但可能被外部改变的硬件寄存器
volatile const uint32_t *STATUS_REG = (uint32_t*)0x40005000;
uint32_t current_status = *STATUS_REG; // 每次读取最新值
// *STATUS_REG = 0; // 错误:const禁止写入
2. const + static
// 文件内可见的常量
static const int INTERNAL_CONST = 42;
// 函数内持久化的常量
void counter() {
static const int MAX_COUNT = 100; // 只初始化一次
static int count = 0;
if(++count > MAX_COUNT) reset();
}
总结:const的核心价值
- 安全性:防止意外修改关键数据
- 可读性:明确标识不应修改的值
- 优化提示:帮助编译器进行优化
- 接口设计:清晰表达函数参数和返回值的意图
- 硬件交互:安全访问只读硬件资源
graph TD
A[const用法] --> B[基本常量]
A --> C[指针保护]
A --> D[函数参数]
A --> E[返回值]
A --> F[复合类型]
C --> C1[指向常量的指针]
C --> C2[常量指针]
C --> C3[双重const]
F --> F1[结构体常量]
F --> F2[常量数组]
F --> F3[const成员]
浙公网安备 33010602011771号