嵌入式软件开发中常见知识点问答集锦!

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在多人协助的场合应用居多,每人专注自己的程序模块。

相关推荐
电化学仪器白超1 小时前
EC20CEHDLG-128-SNNS调试记录
python·单片机·嵌入式硬件·自动化
极客小张1 小时前
基于STM32的智能水质监测与远程预警系统设计与实现
c语言·python·stm32·单片机·嵌入式硬件·物联网
2501_918126912 小时前
stm32最级别的烧录解锁是什么?
stm32·单片机·嵌入式硬件·学习·个人开发
Once_day2 小时前
GCC编译(7)链接脚本LinkerScripts
c语言·c++·编译和链接·程序员自我修养
qq_241585612 小时前
jump_to_app
单片机·嵌入式硬件
小刘爱玩单片机2 小时前
【stm32简单外设篇】- KY-025 干簧管(磁控)模块
c语言·stm32·单片机·嵌入式硬件
forAllforMe2 小时前
STM32的分散加载问题--使用场合
stm32·单片机·嵌入式硬件
姜太公钓鲸2332 小时前
NVIC嵌套向量中断控制器是什么?作用是什么?
stm32·单片机·嵌入式硬件
代码游侠2 小时前
STM32开发——基础外设
linux·运维·arm开发·stm32·单片机·嵌入式硬件·学习