嵌入式C语言

1. 指针函数

本质:返回值是指针的函数

c 复制代码
// 定义:函数名先和()结合,返回
int* int* fun(int a, int b);

字节数 :函数本身不占内存,返回的指针占 4/8 字节(32 位系统 4 字节,64 位系统 8 字节)

8位系统:51单片机,指针占2个字节

32位系统:STM32,ESP32,指针占4字节

64位系统:极少,工业高端芯片,指针占8个字节

32 位 Windows/Linux**所有指针统一占 4 字节

64 位 Windows/Linux(现在主流)所有指针统一占 8 字节

底层原理:返回值是一个内存地址(RAM / 寄存器地址)

真实用途

  1. 返回缓冲区首地址
  2. 返回硬件数据首地址
c 复制代码
// 底层驱动:返回接收缓冲区指针 
uint8_t* UART_GetRxBuffer(void) { 
    return &uart_rx_buf[0]; }

2. 函数指针

本质:指向函数的指针变量

c 复制代码
// 定义:指针先和*结合,再指向函数 
int (*pfun)(int a, int b);

字节数固定 4/8 字节(所有指针都一样)

底层原理

  1. 函数名 = 函数在 Flash 中的地址
  2. 函数指针 = 存这个地址的变量

真实用途(必须用)

  1. 中断回调函数
  2. 硬件驱动统一接口
  3. 状态机、调度器
  4. bootloader 跳转应用程序

真实底层代码(中断回调)

c 复制代码
// 定义函数指针类型
typedef void (*CallbackFunc)(void);

// 底层驱动注册中断回调
void GPIO_RegisterIRQ(CallbackFunc cb) {
    // 硬件触发时,自动调用你传入的函数
    pCallback = cb;
}

// 上层应用写自己的中断函数
void my_handler(void) {
    // 点灯、读按键
}

// 注册
GPIO_RegisterIRQ(my_handler);

为什么底层必须用函数指针?

  • 底层驱动不知道上层要干嘛
  • 只提供钩子(函数指针)
  • 硬件触发 → 调用地址 → 执行用户逻辑

3. 数组指针(行指针)

本质:指向一维数组的指针

c 复制代码
// 定义:指针先和*结合,再指向数组 
int (*p)[5]; // 指向包含5个int的一维数组

字节数固定 4/8 字节

  • 底层原理

int (*p)[10];指向一整行数组 ,用于二维数组(屏显存、表格、寄存器表)

  • 真实用途
  1. LCD 显存操作
  2. Flash 分区表
  3. 多行配置参数
c 复制代码
// LCD 一行 800 像素 
uint16_t (*line_ptr)[800] = (uint16_t(*)[800])0xC0000000;

4. 指针数组

本质:存放指针的数组

c 复制代码
// 定义:[]优先级高,先和数组结合 
int *p[5]; // 数组里有5个int*类型指针

字节数元素个数 × 指针大小

  • 例:int *p[5] → 5×8=40 字节(64 位)

底层原理

类型* 数组名[N]里面存 N 个地址

真实用途

  1. 多个设备的寄存器基地址
  2. 多个回调函数表
  3. 字符串表(日志、命令)
c 复制代码
// 3个串口基地址
uint32_t* uart_base[] = {
    (uint32_t*)0x40001000,
    (uint32_t*)0x40002000,
    (uint32_t*)0x40003000
};

5. 各数据类型字节数(64 位系统)

类型 字节数
char 1
short 2
int / long 4
long long 8
float 4
double 8
所有指针类型 8

32 位系统:所有指针都是 4 字节

嵌入式真实底层规则: 绝对不用 int、long,只用 stdint.h 固定大小类型!

6. 排序算法

冒泡排序(标准模板)

c 复制代码
void bubbleSort(int arr[], int n) {
    // 外层:控制轮数,n-1轮
    for (int i = 0; i < n - 1; i++) {
        // 内层:两两比较
        for (int j = 0; j < n - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
  • 核心:相邻比较,大的往后冒

  • 时间复杂度:O(n²)

  • 真实用途:

  1. 按键扫描排序
  2. ADC 采样去抖(取中间值)
  3. 数据滤波

嵌入式不会拿来排序大数据,只用来处理小批量硬件数据

7. 关键字

const 用法(3 句记完)

  1. const int a :常量,值不能改
  2. *const int p :指针指向的内容不能改,指针本身能改
  3. *int const p :指针本身地址不能改,指向内容能改

口诀:const 后面跟谁,谁就不能改

底层原理

  • const 变量存在 Flash
  • 非 const 存在 RAM

嵌入式 RAM 极小(1~20KB),能放 Flash 绝不放 RAM

真实用法

c 复制代码
// 存在Flash,不占RAM 
const uint8_t log_table[] = "AT+CONNECT\r\n"; 
const uint32_t PIN_CONFIG = 0x00010001;

const = 放 Flash,省 RAM

static 用法(3 大核心)

  1. 修饰局部变量 :延长生命周期,只初始化一次
  2. 修饰全局变量 :只能在本文件使用,外部文件不可见
  3. 修饰函数 :只能在本文件调用,外部文件不可见

底层原理

  1. static 局部变量 :存在 RAM 全局区,不释放
  2. static 全局变量 / 函数 :只在本文件可见(防止命名冲突

真实用途(驱动必写)

c 复制代码
/// 只能本文件调用,防止外部乱改
static void GPIO_Config(void) {
    // 操作寄存器
}

// 中断计数,不会被销毁
static uint32_t irq_count = 0;
为什么底层必须用 static?
  • 嵌入式文件多
  • 防止函数重名
  • 保护硬件状态不被外部篡改
  • 中断变量必须 static

static = 保护硬件、防止冲突、中断变量

8. 先判断再遍历 vs 先遍历再判断

1. 先判断再遍历(嵌入式首选)

c 复制代码
if(条件){ 
    循环遍历; }

优点

  • 条件不满足时,直接跳过循环,效率极高
  • 代码逻辑清晰,减少无效循环

缺点

  • 必须提前知道条件,无法在循环中动态判断

底层原理

  • 不满足条件不进循环
  • 省电、省 CPU
  • 嵌入式 CPU 资源极低,必须这样写

真实场景

c 复制代码
if(UART_RX_READY()) {
    // 有数据才遍历
    for(int i=0; i<len; i++) {
        buf[i] = UART->DR;
    }
}

2. 先遍历再判断(极少用)

c 复制代码
循环遍历{ 
    if(条件){ 
        执行操作; 
    } 
}

优点

  • 可以遍历中动态判断,灵活处理每个元素
  • 适合不知道满足条件的位置的场景

缺点

  • 每次都要进入循环,无效循环多,效率低
  • CPU 一直跑
  • 费电、发热、占用资源
  • 只有轮询按键、屏幕刷新才偶尔用

C语言 位操作 清除第三位

相关推荐
凉、介3 小时前
深入理解 ARMv8-A|异常/中断处理
笔记·学习·嵌入式·arm
济6174 小时前
ROS开发专栏---基于 NAV2 实现仿真环境自主导航实验--适配Ubuntu 22.04
嵌入式硬件·嵌入式·ros2·机器人方向
济6174 小时前
ROS开发专栏---基于开源导航插件 wp_map_tools 多航点巡航导航实验--适配Ubuntu 22.04
ubuntu·嵌入式·ros2·机器人开发·机器人方向
加成BUFF20 小时前
机器人专业2025年12月5日《嵌入式系统STM32》期末考试范围+试卷
stm32·嵌入式·期末复习
不脱发的程序猿1 天前
如何让Skill同时跑在Cursor、Codex和Claude Code里?
单片机·嵌入式硬件·嵌入式
底层开发智库1 天前
C1-Ultra FVP调试并运行Linux kernel全程记录,硬核演示如何解决启动问题
linux·arm开发·内核·嵌入式·arm
秋越2 天前
软考中级嵌入式——第十七章 多媒体基础知识
嵌入式·多媒体·软考中级·嵌入式系统设计师
lularible2 天前
从沙子到车辙(4.2):从片内到片间——SPI、I2C
开源·嵌入式·汽车电子
不脱发的程序猿2 天前
如何创建一个标准Skill,让嵌入式经验真正复用起来
人工智能·单片机·嵌入式硬件·嵌入式·skill