1 const关键字的具体作用和用途?
const主要用来修饰只读变量,告诉编译器:这个标识符所指向的内容是只读的,如果程序试图修改它,编译器就会直接报错。其作用体现在安全性、可读性两个方面。
常见用途:
(1)用来修饰只读变量,比如定义一个常数 const double PI =3.1415926;
或者定义一个常数数组 const graph[]={0x01, 0x02, 0x03, 0x04}; 可以拦截修改操作,减少BUG;
(2)修饰函数参数,比如修饰一个函数的形参,该形参在函数内部不能被修改,避免误操作,同时提高代码的可读性(一眼就看出这个参数是"输入型"参数,只读取不修改)。
cpp
// const修饰char* str:限定函数内部不能修改str指向的字符串内容
void print_str(const char* str)
{
// str[0] = 'H'; // 编译报错:assignment of read-only location '*str'
printf("字符串:%s\n", str);
}
2 volatile关键字的具体作用和用途?
volatile的主要作用是告诉编译器:这个变量可能被外部触发条件(比如硬件、中断、线程等改变)意外修改,编译器不用对变量进行任何修改,每次读取变量时都是从内存中读取,而不是从寄存器中读取缓存值。
常见用途:
(1)访问硬件寄存器
硬件寄存器的值会被硬件自动修改,程序必须实时读取内存中的真是值。为达到访问硬件寄存器真实值的目的,比如用一个指针指向某个寄存器地址,然后加上volatile。
cpp
// 示例:读取硬件串口数据寄存器(伪代码,模拟嵌入式场景)
#include <stdio.h>
// 定义串口数据寄存器的内存地址(volatile修饰,强制每次读内存)
#define UART_DATA_REG (*(volatile unsigned char*)0x1000)
// 读取串口数据,直到有数据可读
unsigned char read_uart_data() {
// 编译器不会优化这个循环:每次都从0x1000内存地址读真实值
while (UART_DATA_REG == 0) {
// 等待硬件传入数据
}
return UART_DATA_REG; // 读取最新的硬件数据
}
int main() {
unsigned char data = read_uart_data();
printf("串口读取到的数据:%d\n", data);
return 0;
}
(2)中断/多线程中的共享变量
在中断服务程序或者多线程程序中,一个变量可能被中断或者其它线程修改,volatile能保证每次访问的都是内存中的最新值。
cpp
// 示例:中断程序中的共享标志位(伪代码)
#include <stdio.h>
// 共享标志位:被主程序和中断程序共同访问,必须加volatile
volatile int interrupt_flag = 0;
// 模拟中断处理函数(硬件触发时执行)
void interrupt_handler() {
interrupt_flag = 1; // 中断触发,修改标志位
}
int main() {
// 主循环:检测中断标志位
while (1) {
// 不加volatile的话,编译器可能优化成:只读一次interrupt_flag,之后永远用这个值
// 加了volatile后,每次都读内存中的最新值
if (interrupt_flag == 1) {
printf("检测到中断,处理中...\n");
interrupt_flag = 0; // 清除标志位
break;
}
}
return 0;
}
3 static关键字的具体作用和用途?
static修饰的变量,存储在全局区/静态区,在程序运行期间一直存在可以随时读写;同时限制全局变量和函数的作用域在当前.c文件。主要起到一个隐藏、封装变量/函数,避免暴露不必要的接口。
常见用途
(1)修饰全局变量
限制作用域:限制全局变量的作用域在当前.c文件,其它外部.c文件不能对该变量进行读写,起到一个隐藏和封装细节的作用。
避免命名冲突:允许多个.c文件命名相同名字的变量,避免"重命名"报错。
(2)修饰函数
限制作用域:限制全局变量的作用域在当前.c文件,其它外部.c文件不能对该变量进行读写,起到一个隐藏和封装细节的作用。
避免命名冲突:允许多个.c文件命名相同名字的变量,避免"重命名"报错。
(3)修饰数组
static修饰数组时,本质和修饰变量一致,核心是将数组存储到静态区,避免栈溢出(栈空间通常较小,大数组建议用static)。
cpp
#include <stdio.h>
void big_array() {
// 普通大数组:栈空间不足,可能导致栈溢出
// int arr[1024*1024]; // 4MB数组,栈通常只有几MB,易崩溃
// static数组:存储在静态区,无栈溢出风险
static int arr[1024*1024] = {0};
arr[0] = 10;
printf("static数组第一个元素:%d\n", arr[0]);
}
int main() {
big_array();
return 0;
}
可见,static在多人协助的场合应用居多,每人专注自己的程序模块。