读书笔记-《嵌入式C语言自我修养 从芯片、编译器到操作系统》
·
嵌入式C语言自我修养 从芯片、编译器到操作系统
《嵌入式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与内存速度不匹配
指令执行流程
- 取指:PC指向的地址取指令
- 译码:分析指令操作码
- 执行:ALU执行运算
- 访存:读写内存
- 写回:结果写回寄存器
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语言开发所需的核心知识和技能,主要内容包括:
- 开发工具:Vim、GCC、make、Git的使用
- 硬件基础:CPU工作原理、ARM体系结构、汇编语言
- 编译原理:预处理、编译、汇编、链接的完整流程
- 内存管理:堆栈管理、内存泄漏、段错误的调试
- GNU C扩展:attribute、typeof、零长度数组等高级特性
- 指针深入:数据存储、指针类型、复杂指针声明
- 编程思想:面向对象编程、模块化设计、分层架构
- 操作系统:多任务、进程线程、内存管理、系统调用
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)