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

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

相关推荐
leo__52017 小时前
C# 虚拟键盘(软键盘)实现
单片机·c#·计算机外设
你疯了抱抱我17 小时前
【STM32】使用 STM32CubeMX 生成项目,LED测试;上位机:STM32F411CEU6
stm32·单片机·嵌入式硬件
wuminyu17 小时前
Java锁机制之park和unpark源码剖析
java·linux·c语言·jvm·c++
asdfg125896318 小时前
C 语言中产生伪随机数的标准做法
c语言·开发语言
玖玥拾18 小时前
C/C++ 基础笔记(十一)类的进阶
c语言·c++·设计模式·
Soari19 小时前
llama.cpp更新(b9553):LLM inference in C/C++,本地和云端实现高性能大模型推理
c语言·c++·llama
今天的你比昨天进步了?19 小时前
单片机程序,keil可以正常编译,VScode编译报错处理
vscode·单片机·嵌入式硬件
2601_9611940219 小时前
考研资料电子版|去哪找|网盘
java·c语言·c++·python·考研·php
十月的皮皮20 小时前
C语言学习笔记202606008- 三角形判断(3种方法)
c语言·笔记·学习