本节重点讲述类型修饰符关键字const和volatile的概念及使用,如果想详细了解关键字的同学点击下方链接进行跳转
1-1 C语言 - 关键字及其使用(数据类型)-CSDN博客
1-2 C语言 - 控制语句关键字-CSDN博客
1-3 C语言 - 控制语句的使用注意事项(这些绝对是您经常出错的地方)-CSDN博客
1-4 C语言 - 存储类别关键字及其使用(超详细)-CSDN博客
目录
const 关键字
const 的使用场景
示例 1:声明常量
示例 2:指针修饰
示例 3:函数参数
volatile 关键字
volatile 的使用场景
示例 1:硬件寄存器
示例 2:多线程编程
示例 3:信号处理
注意事项及易错点
const 使用
volatile 使用
const
关键字
const
关键字用于声明常量,其作用是防止变量的值被修改。这有助于提高代码的安全性和可读性,同时也允许编译器进行更多的优化。
const
的使用场景
- 常量数据:声明不变的常量数据。
- 指针修饰:用于修饰指针,表示指针所指向的数据或指针本身是常量。
- 函数参数:在函数参数中使用
const
,表示函数不会修改传入的参数。
示例 1:声明常量
const int MAX_SIZE = 100;
MAX_SIZE
被声明为常量,值为 100,之后的代码中不能修改 MAX_SIZE
的值。
示例 2:指针修饰
const int* ptr; // ptr 是指向 const int 的指针,不能通过 ptr 修改 int 的值
int* const ptr2; // ptr2 是 const 指针,不能修改 ptr2 本身,但可以修改其指向的值
const int* const ptr3; // ptr3 是指向 const int 的 const 指针,不能修改 ptr3 或其指向的值
示例 3:函数参数
void printArray(const int* arr, int size) {for (int i = 0; i < size; ++i) {printf("%d ", arr[i]);}// arr[i] = 5; // 错误:不能修改 const int* 指针所指向的数据
}
函数 printArray
接收一个 const int*
参数,这表示 printArray
函数不会修改 arr
数组的内容。
volatile
关键字
volatile
关键字用于声明一个变量的值可能会被程序外部的因素(如硬件或其他线程)改变。这告诉编译器,每次访问该变量时都必须从内存中读取最新的值,而不是使用寄存器中的缓存值。
volatile
的使用场景
- 硬件寄存器:当变量对应硬件寄存器时,硬件可能在后台改变寄存器的值。
- 多线程编程:在多线程编程中,当一个变量在不同的线程之间共享并可能被任意线程修改时。
- 信号处理:在处理异步信号时,信号处理函数可能修改某些全局变量。
示例 1:硬件寄存器
volatile int* port = (volatile int*)0x4000; // 假设 0x4000 是硬件端口地址
port
是一个指向硬件寄存器的指针,volatile
确保每次访问 *port
都获取最新的值。
示例 2:多线程编程
volatile int flag = 0;void thread1() {flag = 1; // 修改 flag 的值
}void thread2() {while (flag == 0) {// 等待 flag 变为 1}// 继续执行
}
flag
被声明为 volatile
,确保 thread2
能够正确读取到 thread1
修改后的值。
示例 3:信号处理
volatile sig_atomic_t signalFlag = 0;void signalHandler(int signal) {signalFlag = 1;
}int main() {signal(SIGINT, signalHandler);while (!signalFlag) {// 等待信号}printf("Signal received.\n");return 0;
}
signalFlag
被声明为 volatile
,确保主程序在信号处理程序修改 signalFlag
后能立即读取到更新的值。
注意事项及易错点
const
和 volatile
关键字在 C/C++ 编程中的正确使用可以提高代码的安全性、可读性和性能,但在使用过程中也有一些需要注意的事项和易错点。
const
使用
-
常量初始化
const
变量必须在声明时进行初始化,因为它们的值不能在之后被修改。-
const int x; // 错误:未初始化 const int y = 10; // 正确:在声明时初始化
-
指针和
const
- 指针与
const
的组合可能会引起混淆,特别是理解指针本身是否是常量以及指针所指向的数据是否是常量。 -
const int* p1; // 指向 const int 的指针,不能通过 p1 修改 int 的值 int* const p2; // const 指针,不能修改 p2 本身,但可以修改其指向的值 const int* const p3; // 指向 const int 的 const 指针,不能修改 p3 或其指向的值
- 指针与
-
函数参数
- 使用
const
修饰函数参数时,确保理解其含义:传递const
指针意味着函数不能修改指针所指向的数据,但可以修改指针本身。 -
void foo(const int* p); // p 是指向 const int 的指针,不能通过 p 修改 int 的值
- 使用
-
返回值
- 如果函数返回指针,使用
const
可以防止调用者修改函数返回的数据。 -
const int* getArray();
- 如果函数返回指针,使用
-
volatile
使用 -
避免优化
- 使用
volatile
的目的是告诉编译器不要优化对变量的访问,以确保每次访问都是从内存中读取最新的值。 -
volatile int flag = 0;
- 使用
-
硬件寄存器
- 在嵌入式编程中,通常会将硬件寄存器声明为
volatile
,以确保每次访问寄存器时都能读取到最新的硬件状态。 -
volatile int* port = (volatile int*)0x4000;
- 在嵌入式编程中,通常会将硬件寄存器声明为
-
多线程编程
- 在多线程编程中,使用
volatile
确保变量的修改在不同线程之间可见。但需要注意的是,volatile
并不能保证线程安全,通常需要与其他同步机制(如互斥锁、信号量等)结合使用。 -
volatile int flag = 0;
- 在多线程编程中,使用
-
信号处理
- 在信号处理函数中使用
volatile
确保信号处理程序修改的全局变量能被主程序正确读取。 -
volatile sig_atomic_t signalFlag = 0;
- 在信号处理函数中使用