《嵌入式C语言自我修养》读书笔记
知识框架
在这里插入图片描述

知识框架

┌─────────────────────────────────────────────────────────────────────────────┐
│                        嵌入式C语言完整知识体系                                │
├─────────────────────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  开发工具   │  │  硬件基础   │  │  编译原理   │  │  内存管理   │        │
│  │  • Vim     │  │  • CPU      │  │  • 预处理   │  │  • 栈管理   │        │
│  │  • make    │  │  • ARM      │  │  • 编译     │  │  • 堆管理   │        │
│  │  • Git     │  │  • 体系结构 │  │  • 链接     │  │  • mmap    │        │
│  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  GNU C扩展  │  │  指针与存储 │  │  编程思想   │  │  操作系统   │        │
│  │  • attribute│  │  • 数据对齐 │  │  • OOP     │  │  • 多任务   │        │
│  │  • typeof   │  │  • 指针类型 │  │  • 模块化   │  │  • 进程线程 │        │
│  │  • 零长度数组│  │  • 数组指针 │  │  • 框架     │  │  • 内存管理 │        │
│  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘        │
└─────────────────────────────────────────────────────────────────────────────┘

第1章:开发工具

1.1 Vim编辑器

基本命令速查表

操作类型命令说明
光标移动h/j/k/l左/下/上/右
单词移动w/b/e下一单词开头/上一单词开头/词尾
行移动0/$/^行首/行尾/第一个非空字符
屏幕移动gg/G文件开头/末尾
插入模式i/a/o光标前插入/后插入/下一行插入
删除x/dd/dw删除字符/删除行/删除单词
复制粘贴yy/p复制行/粘贴
查找替换/string查找字符串
保存退出:wq/:q!保存退出/强制退出

Vim配置文件(~/.vimrc)示例

set number          "显示行号
set autoindent      "自动缩进
set tabstop=4       "Tab键宽度
set shiftwidth=4    "缩进宽度
syntax on           "语法高亮

"括号自动补全
inoremap [ []<ESC>i
inoremap ( ()<ESC>i
inoremap { {<CR>}<ESC>O

1.2 GCC编译工具

常用编译选项

gcc -E main.c -o main.i      # 只预处理
gcc -S main.c -o main.s      # 编译到汇编
gcc -c main.c -o main.o      # 编译不链接
gcc main.o -o hello          # 链接生成可执行文件
gcc -g main.c                # 生成调试信息
gcc -O2 main.c               # 优化等级2
gcc -I./include main.c       # 指定头文件路径
gcc -L./lib -lxxx main.c     # 指定库路径和库名

1.3 Makefile基本写法

CC = gcc
CFLAGS = -Wall -O2
TARGET = hello
OBJS = main.o sub.o

$(TARGET): $(OBJS)
    $(CC) $(OBJS) -o $(TARGET)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f $(OBJS) $(TARGET)

.PHONY: clean

1.4 Git基本操作

git init                    # 初始化仓库
git add main.c              # 添加到暂存区
git commit -m "message"     # 提交到本地仓库
git log                     # 查看提交历史
git branch my_branch        # 创建分支
git checkout my_branch      # 切换分支
git merge my_branch         # 合并分支

第2章:计算机体系结构与CPU

2.1 CPU工作原理

CPU内部结构

  • ALU:算术逻辑单元,负责运算
  • 控制单元:取指令、译码、执行控制
  • 寄存器:PC(程序计数器)、SP(栈指针)、LR(链接寄存器)
  • Cache:L1/L2/L3缓存,解决CPU与内存速度不匹配

指令执行流程

  1. 取指:PC指向的地址取指令
  2. 译码:分析指令操作码
  3. 执行:ALU执行运算
  4. 访存:读写内存
  5. 写回:结果写回寄存器

2.2 流水线技术

三级流水线示例

时钟周期1: 取指 指令1
时钟周期2: 译码 指令1   取指 指令2
时钟周期3: 执行 指令1   译码 指令2   取指 指令3
时钟周期4:           执行 指令2   译码 指令3   取指 指令4

2.3 大小端模式

判断大小端的程序

#include <stdio.h>

// 方法1:指针法
int check_endian1(void) {
    int a = 0x12345678;
    char *p = (char *)&a;
    return (*p == 0x78) ? 1 : 0;  // 1:小端, 0:大端
}

// 方法2:联合体法
int check_endian2(void) {
    union {
        int a;
        char b;
    } u;
    u.a = 1;
    return u.b;  // 1:小端, 0:大端
}

int main() {
    if (check_endian1())
        printf("Little Endian\n");
    else
        printf("Big Endian\n");
    return 0;
}

第3章:ARM汇编基础

3.1 ARM常用指令

指令说明示例
MOV数据传送MOV R0, #1
ADD/SUB加/减ADD R0, R1, R2
LDR/STR加载/存储LDR R0, [R1]
PUSH/POP入栈/出栈PUSH {R0-R3, LR}
B/BL跳转BL func
CMP比较CMP R0, #0
BEQ/BNE条件跳转BEQ label

3.2 函数调用汇编分析

C代码

int add(int a, int b) {
    return a + b;
}

int main() {
    int c = add(3, 4);
    return 0;
}

对应的ARM汇编

add:
    push {fp, lr}       @ 保存帧指针和返回地址
    add fp, sp, #4      @ 设置帧指针
    sub sp, sp, #8      @ 分配栈空间
    str r0, [fp, #-8]   @ 保存参数a
    str r1, [fp, #-12]  @ 保存参数b
    ldr r2, [fp, #-8]   @ 加载a
    ldr r3, [fp, #-12]  @ 加载b
    add r0, r2, r3      @ a+b结果存r0
    sub sp, fp, #4      @ 恢复栈指针
    pop {fp, pc}        @ 恢复帧指针并返回

main:
    push {fp, lr}
    add fp, sp, #4
    sub sp, sp, #8
    mov r0, #3          @ 第一个参数
    mov r1, #4          @ 第二个参数
    bl add              @ 调用add函数
    str r0, [fp, #-8]   @ 保存返回值到c
    mov r0, #0          @ return 0
    sub sp, fp, #4
    pop {fp, pc}

第4章:编译、链接与运行

4.1 编译流程

C源文件(.c) 
    → 预处理(.i)    # 处理#include、#define等
    → 编译(.s)      # 生成汇编代码
    → 汇编(.o)      # 生成目标文件
    → 链接          # 链接目标文件和库
    → 可执行文件

查看编译中间结果

# 预处理
gcc -E hello.c -o hello.i

# 编译到汇编
gcc -S hello.c -o hello.s

# 编译不链接
gcc -c hello.c -o hello.o

# 查看目标文件信息
readelf -h a.out       # 查看文件头
readelf -S a.out       # 查看节头表
objdump -d a.out       # 反汇编

4.2 静态库制作

制作和使用静态库

# 编译源文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o

# 打包成静态库
ar rcs libcalc.a add.o sub.o

# 使用静态库
gcc main.c -L. -lcalc -o main

4.3 动态库制作

制作和使用动态库

# 编译成位置无关代码
gcc -fPIC -c add.c -o add.o
gcc -fPIC -c sub.c -o sub.o

# 创建动态库
gcc -shared add.o sub.o -o libcalc.so

# 使用动态库
gcc main.c -L. -lcalc -o main

# 设置库路径
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

4.4 链接脚本示例

OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

SECTIONS
{
    . = 0x30000000;  /* 链接起始地址 */
    
    .text : {
        *(.text)
        *(.text.*)
    }
    
    .rodata : {
        *(.rodata)
        *(.rodata.*)
    }
    
    .data : {
        *(.data)
        *(.data.*)
    }
    
    .bss : {
        __bss_start = .;
        *(.bss)
        *(.bss.*)
        *(COMMON)
        __bss_end = .;
    }
}

第5章:内存堆栈管理

5.1 栈帧分析

函数调用栈布局

void func2(int a) {
    int x = a;
}

void func1(int a, int b) {
    int y = a + b;
    func2(y);
}

int main() {
    func1(3, 4);
    return 0;
}

栈内存变化

高地址
+-----------------+ <-- 初始栈底
| main函数栈帧    |
| - 局部变量      |
| - 返回地址      |
+-----------------+
| func1函数栈帧   |
| - 参数a,b       |
| - 局部变量y     |
| - 返回地址      |
+-----------------+
| func2函数栈帧   |
| - 参数x         |
| - 局部变量      |
| - 返回地址      |
+-----------------+ <-- 当前栈顶
低地址

5.2 堆内存管理

malloc/free基本使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // 申请内存
    int *p = (int *)malloc(10 * sizeof(int));
    if (p == NULL) {
        printf("malloc failed\n");
        return -1;
    }
    
    // 使用内存
    for (int i = 0; i < 10; i++) {
        p[i] = i;
    }
    
    // 释放内存
    free(p);
    p = NULL;  // 避免野指针
    
    return 0;
}

5.3 内存泄漏检测

使用Valgrind检测内存泄漏

# 安装Valgrind
sudo apt-get install valgrind

# 编译程序(加-g选项)
gcc -g test.c -o test

# 运行Valgrind
valgrind --leak-check=full ./test

内存泄漏示例

#include <stdlib.h>

void memory_leak(void) {
    int *p = (int *)malloc(100);
    // 忘记free(p)
}

int main() {
    memory_leak();
    return 0;
}

/* Valgrind输出:
==12345== 100 bytes in 1 blocks are definitely lost
==12345==    at 0x4C2B800: malloc (vg_replace_malloc.c:299)
==12345==    by 0x4004E7: memory_leak (test.c:4)
==12345==    by 0x4004F3: main (test.c:9)
*/

5.4 内存越界检测

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *p = (int *)malloc(5 * sizeof(int));
    
    // 内存越界
    for (int i = 0; i <= 5; i++) {  // 错误:i=5时越界
        p[i] = i;
    }
    
    free(p);
    return 0;
}

第6章:GNU C扩展语法

6.1 指定初始化

数组指定初始化

// 传统方式
int a[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// GNU C指定初始化
int b[10] = {[0] = 1, [5] = 2, [9] = 3};

// 范围初始化
int c[100] = {[10 ... 20] = 1, [30 ... 40] = 2};

结构体指定初始化

struct student {
    char name[20];
    int age;
    int score;
};

// 传统方式
struct student stu1 = {"Tom", 18, 90};

// GNU C指定初始化
struct student stu2 = {
    .name = "Jerry",
    .age = 19,
    .score = 95
};

6.2 语句表达式

宏定义的进化

// 初级版:有优先级问题
#define MAX1(x, y) x > y ? x : y

// 改进版:加括号解决优先级
#define MAX2(x, y) ((x) > (y) ? (x) : (y))

// 高级版:使用语句表达式,解决副作用
#define MAX3(x, y) ({ \
    typeof(x) _x = (x); \
    typeof(y) _y = (y); \
    _x > _y ? _x : _y; \
})

// 终极版:支持任意类型
#define MAX(type, x, y) ({ \
    type _x = (x); \
    type _y = (y); \
    _x > _y ? _x : _y; \
})

// 使用示例
int a = 5, b = 6;
int max = MAX(int, a++, b++);  // a只自增一次

6.3 container_of宏

container_of宏定义

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({ \
    const typeof(((type *)0)->member) *__mptr = (ptr); \
    (type *)((char *)__mptr - offsetof(type, member)); \
})

// 使用示例
struct student {
    char name[20];
    int age;
    int score;
};

int main() {
    struct student stu = {"Tom", 18, 90};
    int *p = &stu.age;  // 只知道age成员的地址
    
    // 通过age地址获取整个结构体地址
    struct student *ps = container_of(p, struct student, age);
    printf("name: %s, age: %d, score: %d\n", 
           ps->name, ps->age, ps->score);
    
    return 0;
}

6.4 零长度数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 变长结构体
struct buffer {
    int len;
    char data[0];  // 零长度数组
};

int main() {
    int msg_len = 20;
    
    // 申请结构体+数据空间
    struct buffer *buf = malloc(sizeof(struct buffer) + msg_len);
    buf->len = msg_len;
    strcpy(buf->data, "Hello, World!");
    
    printf("data: %s\n", buf->data);
    
    free(buf);
    return 0;
}

6.5 __attribute__属性

aligned和packed

#include <stdio.h>

// 默认对齐
struct default_struct {
    char a;
    int b;
    short c;
};  // size = 12 (4+4+2+2填充)

// 1字节对齐,无填充
struct __attribute__((packed)) packed_struct {
    char a;
    int b;
    short c;
};  // size = 7 (1+4+2)

// 指定8字节对齐
struct __attribute__((aligned(8))) aligned_struct {
    char a;
    int b;
};  // size = 8 (4+4, 按8对齐)

int main() {
    printf("default: %lu\n", sizeof(struct default_struct));
    printf("packed: %lu\n", sizeof(struct packed_struct));
    printf("aligned: %lu\n", sizeof(struct aligned_struct));
    return 0;
}

format属性

#include <stdio.h>
#include <stdarg.h>

// 告诉编译器按printf格式检查
void __attribute__((format(printf, 1, 2))) my_printf(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

int main() {
    my_printf("%d\n", 100);      // 正确
    my_printf("%d\n", "hello");  // 编译警告:格式不匹配
    return 0;
}

weak属性

// file1.c
#include <stdio.h>

void __attribute__((weak)) func(void) {
    printf("weak func\n");
}

// file2.c
#include <stdio.h>

void func(void) {
    printf("strong func\n");
}

// main.c
void func(void);  // 声明

int main() {
    func();  // 如果有强符号,调用强符号;否则调用弱符号
    return 0;
}

6.6 likely/unlikely

#include <stdio.h>

#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

int main(int argc, char *argv[]) {
    int a = argc;
    
    if (likely(a == 1)) {
        printf("a is 1 (likely)\n");
    } else {
        printf("a is not 1 (unlikely)\n");
    }
    
    return 0;
}

第7章:指针与存储

7.1 指针的本质

#include <stdio.h>

int main() {
    int a = 100;
    int *p = &a;      // p保存a的地址
    int **pp = &p;    // pp保存p的地址
    
    printf("a = %d\n", a);        // 直接访问
    printf("*p = %d\n", *p);      // 一级指针访问
    printf("**pp = %d\n", **pp);  // 二级指针访问
    
    // 指针大小
    printf("sizeof(int*): %lu\n", sizeof(int*));
    printf("sizeof(char*): %lu\n", sizeof(char*));
    printf("sizeof(void*): %lu\n", sizeof(void*));
    
    return 0;
}

7.2 指针运算

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p = arr;
    
    printf("p = %p, *p = %d\n", p, *p);       // arr[0]
    printf("p+1 = %p, *(p+1) = %d\n", p+1, *(p+1)); // arr[1]
    printf("p+2 = %p, *(p+2) = %d\n", p+2, *(p+2)); // arr[2]
    
    // 指针相减
    int *p1 = &arr[1];
    int *p2 = &arr[4];
    printf("p2 - p1 = %ld\n", p2 - p1);  // 3,表示相隔3个元素
    
    return 0;
}

7.3 数组与指针

#include <stdio.h>

int main() {
    int a[5] = {1, 2, 3, 4, 5};
    
    // 数组名与指针
    printf("a = %p\n", a);        // 数组首地址
    printf("&a[0] = %p\n", &a[0]); // 同上
    printf("&a = %p\n", &a);      // 整个数组的地址,数值相同
    
    // 指针运算的区别
    printf("a+1 = %p\n", a+1);    // 下一个元素
    printf("&a+1 = %p\n", &a+1);  // 跳过整个数组
    
    // 下标访问的本质
    printf("a[2] = %d\n", a[2]);          // 数组方式
    printf("*(a+2) = %d\n", *(a+2));      // 指针方式
    printf("2[a] = %d\n", 2[a]);          // 奇怪的写法,但合法
    
    return 0;
}

7.4 指针数组 vs 数组指针

#include <stdio.h>

int main() {
    // 指针数组:元素是指针的数组
    char *str_arr[] = {"Hello", "World", "C Language"};
    
    for (int i = 0; i < 3; i++) {
        printf("%s\n", str_arr[i]);
    }
    
    // 数组指针:指向数组的指针
    int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int (*p)[3] = arr;  // p指向包含3个int的一维数组
    
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", p[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

7.5 函数指针

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int sub(int a, int b) {
    return a - b;
}

// 函数指针作为参数
int calc(int (*op)(int, int), int x, int y) {
    return op(x, y);
}

int main() {
    // 定义函数指针
    int (*fp)(int, int);
    
    // 指向add函数
    fp = add;
    printf("add: %d\n", fp(10, 5));
    
    // 指向sub函数
    fp = sub;
    printf("sub: %d\n", fp(10, 5));
    
    // 函数指针作为参数
    printf("calc(add, 10, 5): %d\n", calc(add, 10, 5));
    printf("calc(sub, 10, 5): %d\n", calc(sub, 10, 5));
    
    return 0;
}

第8章:C语言的面向对象编程思想

8.1 封装

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// "类"的定义
struct animal {
    char name[20];
    int age;
    
    // 方法(函数指针)
    void (*speak)(struct animal *this);
    void (*eat)(struct animal *this);
};

// 方法实现
void animal_speak(struct animal *this) {
    printf("%s is speaking\n", this->name);
}

void animal_eat(struct animal *this) {
    printf("%s is eating\n", this->name);
}

// 构造函数
struct animal *animal_create(const char *name, int age) {
    struct animal *obj = malloc(sizeof(struct animal));
    strcpy(obj->name, name);
    obj->age = age;
    obj->speak = animal_speak;
    obj->eat = animal_eat;
    return obj;
}

// 析构函数
void animal_destroy(struct animal *obj) {
    free(obj);
}

int main() {
    struct animal *dog = animal_create("Dog", 3);
    dog->speak(dog);
    dog->eat(dog);
    animal_destroy(dog);
    
    return 0;
}

8.2 继承

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 基类
struct animal {
    char name[20];
    int age;
    void (*speak)(struct animal *this);
};

// 派生类
struct dog {
    struct animal base;  // 继承基类
    char breed[20];      // 扩展属性
    void (*fetch)(struct dog *this);  // 扩展方法
};

// 方法实现
void animal_speak(struct animal *this) {
    printf("%s is speaking\n", this->name);
}

void dog_speak(struct animal *this) {
    printf("Woof! Woof!\n");
}

void dog_fetch(struct dog *this) {
    printf("%s is fetching the ball\n", this->base.name);
}

// 构造函数
struct dog *dog_create(const char *name, int age, const char *breed) {
    struct dog *obj = malloc(sizeof(struct dog));
    strcpy(obj->base.name, name);
    obj->base.age = age;
    strcpy(obj->breed, breed);
    obj->base.speak = dog_speak;  // 重写方法
    obj->fetch = dog_fetch;
    return obj;
}

int main() {
    struct dog *dog1 = dog_create("Buddy", 2, "Golden");
    
    // 多态:通过基类指针调用
    struct animal *a = (struct animal *)dog1;
    a->speak(a);  // 调用的是dog_speak
    
    // 调用派生类特有方法
    dog1->fetch(dog1);
    
    free(dog1);
    return 0;
}

第9章:模块化编程

9.1 模块组织结构

模块头文件:calc.h

#ifndef __CALC_H__
#define __CALC_H__

// 导出的API
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);

// 数据类型
typedef struct {
    int x;
    int y;
    int result;
} calc_t;

// 初始化函数
void calc_init(calc_t *c);

#endif

模块实现:calc.c

#include "calc.h"
#include <stdio.h>

// 内部函数(static限制作用域)
static void print_result(const char *op, int result) {
    printf("%s result: %d\n", op, result);
}

// 导出函数
int add(int a, int b) {
    int res = a + b;
    print_result("add", res);
    return res;
}

int sub(int a, int b) {
    int res = a - b;
    print_result("sub", res);
    return res;
}

void calc_init(calc_t *c) {
    c->x = 0;
    c->y = 0;
    c->result = 0;
}

主程序:main.c

#include <stdio.h>
#include "calc.h"

int main() {
    calc_t c;
    calc_init(&c);
    
    printf("add(3,4)=%d\n", add(3, 4));
    printf("sub(7,2)=%d\n", sub(7, 2));
    
    return 0;
}

Makefile

CC = gcc
CFLAGS = -Wall -O2
TARGET = calc
OBJS = main.o calc.o

$(TARGET): $(OBJS)
	$(CC) $(OBJS) -o $(TARGET)

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f $(OBJS) $(TARGET)

.PHONY: clean

9.2 回调函数实现

#include <stdio.h>

// 回调函数类型定义
typedef void (*event_handler_t)(int event, void *data);

// 事件处理模块
struct event_manager {
    event_handler_t handler;
    void *private_data;
};

static struct event_manager manager = {NULL, NULL};

// 注册回调
void event_register(event_handler_t handler, void *data) {
    manager.handler = handler;
    manager.private_data = data;
}

// 触发事件
void event_trigger(int event) {
    if (manager.handler) {
        manager.handler(event, manager.private_data);
    }
}

// 应用程序
void my_event_handler(int event, void *data) {
    int *count = (int *)data;
    (*count)++;
    printf("Event %d received, count: %d\n", event, *count);
}

int main() {
    int counter = 0;
    
    event_register(my_event_handler, &counter);
    
    event_trigger(1);
    event_trigger(2);
    event_trigger(3);
    
    return 0;
}

第10章:操作系统入门

10.1 多任务模拟

简单的任务调度器

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

#define MAX_TASKS 4

typedef struct {
    void (*func)(void);
    int interval;
    int counter;
} task_t;

static task_t tasks[MAX_TASKS];
static int task_count = 0;
static volatile int tick = 0;

// 定时器中断模拟
void timer_handler(int sig) {
    tick++;
}

void task_init(void) {
    signal(SIGALRM, timer_handler);
    alarm(1);  // 每秒触发一次
}

void task_register(void (*func)(void), int interval) {
    if (task_count < MAX_TASKS) {
        tasks[task_count].func = func;
        tasks[task_count].interval = interval;
        tasks[task_count].counter = 0;
        task_count++;
    }
}

void task_schedule(void) {
    static int last_tick = 0;
    
    if (tick == last_tick) return;
    last_tick = tick;
    
    for (int i = 0; i < task_count; i++) {
        tasks[i].counter++;
        if (tasks[i].counter >= tasks[i].interval) {
            tasks[i].counter = 0;
            tasks[i].func();
        }
    }
}

// 测试任务
void task1(void) {
    printf("Task1 running\n");
}

void task2(void) {
    printf("  Task2 running\n");
}

void task3(void) {
    printf("    Task3 running\n");
}

int main() {
    task_init();
    task_register(task1, 1);  // 每秒执行
    task_register(task2, 2);  // 每2秒执行
    task_register(task3, 3);  // 每3秒执行
    
    while (1) {
        task_schedule();
        usleep(100000);  // 100ms
    }
    
    return 0;
}

10.2 线程编程

pthread基本使用

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define THREAD_NUM 3

void *thread_func(void *arg) {
    int id = *(int *)arg;
    
    for (int i = 0; i < 5; i++) {
        printf("Thread %d: count %d\n", id, i);
        sleep(1);
    }
    
    pthread_exit(NULL);
}

int main() {
    pthread_t threads[THREAD_NUM];
    int thread_ids[THREAD_NUM];
    
    // 创建线程
    for (int i = 0; i < THREAD_NUM; i++) {
        thread_ids[i] = i;
        if (pthread_create(&threads[i], NULL, 
                           thread_func, &thread_ids[i]) != 0) {
            printf("Failed to create thread %d\n", i);
            return -1;
        }
    }
    
    // 等待线程结束
    for (int i = 0; i < THREAD_NUM; i++) {
        pthread_join(threads[i], NULL);
    }
    
    printf("All threads finished\n");
    return 0;
}

// 编译:gcc -pthread thread_demo.c -o thread_demo

10.3 互斥锁

#include <stdio.h>
#include <pthread.h>

#define LOOP_COUNT 1000000

static int counter = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *arg) {
    for (int i = 0; i < LOOP_COUNT; i++) {
        pthread_mutex_lock(&mutex);
        counter++;  // 临界区
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    
    pthread_create(&t1, NULL, thread_func, NULL);
    pthread_create(&t2, NULL, thread_func, NULL);
    
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    
    printf("Expected: %d\n", LOOP_COUNT * 2);
    printf("Actual: %d\n", counter);
    
    pthread_mutex_destroy(&mutex);
    return 0;
}

10.4 条件变量

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;

void *producer(void *arg) {
    sleep(2);  // 模拟生产数据
    
    pthread_mutex_lock(&mutex);
    ready = 1;
    printf("Producer: data ready\n");
    pthread_cond_signal(&cond);  // 通知消费者
    pthread_mutex_unlock(&mutex);
    
    return NULL;
}

void *consumer(void *arg) {
    pthread_mutex_lock(&mutex);
    
    while (!ready) {
        printf("Consumer: waiting for data...\n");
        pthread_cond_wait(&cond, &mutex);  // 等待条件满足
    }
    
    printf("Consumer: got data\n");
    pthread_mutex_unlock(&mutex);
    
    return NULL;
}

int main() {
    pthread_t prod, cons;
    
    pthread_create(&cons, NULL, consumer, NULL);
    pthread_create(&prod, NULL, producer, NULL);
    
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    
    return 0;
}

10.5 进程间通信

管道通信

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[100];
    
    // 创建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        return -1;
    }
    
    pid = fork();
    
    if (pid == 0) {  // 子进程
        close(pipefd[1]);  // 关闭写端
        
        read(pipefd[0], buffer, sizeof(buffer));
        printf("Child received: %s\n", buffer);
        
        close(pipefd[0]);
    } else {  // 父进程
        close(pipefd[0]);  // 关闭读端
        
        char *msg = "Hello from parent!";
        write(pipefd[1], msg, strlen(msg) + 1);
        
        close(pipefd[1]);
        wait(NULL);
    }
    
    return 0;
}

10.6 共享内存

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

#define SHM_SIZE 1024

int main() {
    int shmid;
    char *shmaddr;
    pid_t pid;
    
    // 创建共享内存
    shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid < 0) {
        perror("shmget");
        return -1;
    }
    
    pid = fork();
    
    if (pid == 0) {  // 子进程
        // 附加共享内存
        shmaddr = shmat(shmid, NULL, 0);
        if (shmaddr == (char *)-1) {
            perror("shmat");
            return -1;
        }
        
        // 读取数据
        printf("Child read: %s\n", shmaddr);
        
        // 分离
        shmdt(shmaddr);
    } else {  // 父进程
        // 附加共享内存
        shmaddr = shmat(shmid, NULL, 0);
        if (shmaddr == (char *)-1) {
            perror("shmat");
            return -1;
        }
        
        // 写入数据
        char *msg = "Hello from parent!";
        strcpy(shmaddr, msg);
        
        wait(NULL);
        
        // 分离并删除
        shmdt(shmaddr);
        shmctl(shmid, IPC_RMID, NULL);
    }
    
    return 0;
}

总结

本书全面系统地讲解了嵌入式C语言开发所需的核心知识和技能,主要内容包括:

  1. 开发工具:Vim、GCC、make、Git的使用
  2. 硬件基础:CPU工作原理、ARM体系结构、汇编语言
  3. 编译原理:预处理、编译、汇编、链接的完整流程
  4. 内存管理:堆栈管理、内存泄漏、段错误的调试
  5. GNU C扩展:attribute、typeof、零长度数组等高级特性
  6. 指针深入:数据存储、指针类型、复杂指针声明
  7. 编程思想:面向对象编程、模块化设计、分层架构
  8. 操作系统:多任务、进程线程、内存管理、系统调用
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐