Linux入门DAY12

📅 2026/8/4 2:05:09 👁️ 阅读次数 📝 编程学习
Linux入门DAY12

#嵌入式开发基础##Linux##C语言#

前言

本篇笔记梳理Linux下gcc四阶段编译流程、C预处理全套语法(宏、头文件、条件编译)与指针核心知识点,是嵌入式Linux C开发的基础重点。预处理负责文本替换,指针直接操作内存地址,二者结合是函数传地址、数组操作、底层开发的核心。

一、gcc编译四阶段(Day12 开篇)

完整流程: main.c → 预处理 → 编译 → 汇编 → 链接 → a.out

1. 预处理(-E)

作用:展开 # 开头代码,处理头文件、宏、条件编译

命令: gcc -E main.c -o main.i

处理内容: #include 、 #define 、 #if/#endif 条件编译

2. 编译(-S)

作用:C代码转为汇编指令

命令: gcc -S main.i -o main.s

3. 汇编(-c)

作用:汇编指令转为二进制目标文件

命令: gcc -c main.s -o main.o

4. 链接(无参数)

作用:链接系统库函数、整合目标文件,生成可执行程序

命令: gcc main.o -o main

二、预处理命令

1. 宏定义 #define

(1)无参宏(常量)

语法: #define 标识符 替换文本

⚠ 核心注意点:

1. 预处理阶段纯文本替换,不做运算;

2. 宏标识符推荐大写,定义末尾不能加分号;

3. 表达式宏建议整体加括号,避免优先级错误;

4. 宏vs函数:宏是文本替换(无调用开销,代码膨胀);函数运行时调用,保存/恢复栈帧;

5. 大量使用宏会增大程序体积。

(2)带参宏(宏函数)

语法: #define 标识符(参数1,参数2) 实现 。

规则:传参只写变量名,不能加数据类型。

2. 头文件包含 #include

1. <头文件> :系统头文件,编译器去 /usr/include 查找;

2. "头文件" :自定义头文件,从当前工程目录查找;

自定义头文件可存放内容

- 嵌套包含其他头文件

- 自定义数据类型(struct/enum)

- 宏定义

- 函数、全局变量声明

3. 条件编译(两大用途)

用途1:防止头文件重复包含(头文件保护宏)

#ifndef 宏名

#define 宏名

// 头文件全部内容

#endif

逻辑:宏未定义则编译内部代码,已定义直接跳过。

用途2:代码分段编译、屏蔽代码

1. #if 逻辑表达式 :表达式为真才编译中间代码, #if 0 可永久屏蔽代码;

2. #ifdef 宏名 :宏已定义则编译代码1,搭配 #else 实现二选一编译;

#ifdef PI

//代码1

#else

//代码2

#endif

三、指针全套知识点

1. 内存、地址、指针基础概念

- 内存:程序运行可访问的存储空间,以字节为最小单位;

- 地址:内存每个字节的编号;

- 指针 = 地址,代表一块内存空间的编号;

- 指针变量:专门存放地址的变量,占用独立内存。

2. 指针变量定义

语法: 基类型 * 变量名;

- 基类型:指针指向内存存储的数据类型;

- * :标识该变量是指针;

- 大小:64位系统占8字节,32位系统占4字节,与指向类型无关。

3. 指针初始化与野指针

1. 野指针:未初始化、指向已释放内存的指针,直接访问会崩溃;

2. 规避方案:- 初始化赋值 NULL (数值0);

直接赋值已有普通变量的地址。

4. 两大核心运算符

(1)取地址运算符 &

作用:获取变量首字节地址

规则:

- 只能作用于变量,不能给常量、表达式取地址;

- &变量 拿到变量起始内存地址。

(2)解引用运算符 *

作用:访问指针指向内存里的数据

规则:

1. 仅放在指针变量左侧使用;

2. *指针 等价于指针指向的普通变量;

3. 读写字节数由指针基类型决定( int* 读写4字节)。

5. 指针算数运算

1. 无意义运算: * / % 不能用于指针;

2. 指针±整数: p+1 向后偏移 sizeof(基类型) 字节, p-1 向前偏移;

3. 指针-指针:仅同类型指针可相减,结果为两个地址间元素个数 (地址差 / sizeof(基类型)) 。

6. 指针作为函数参数(传地址核心考点)

1. 修改主函数变量:传递变量地址,函数内通过 * 修改原值;

2. 只读使用变量:传值/传地址均可;

3. 多返回值:传入外部变量地址,函数内部写入结果。

7. 指针与一维数组

1. 数组名是首元素地址常量,不能赋值修改;

2. 下标等价写法:

- a[0] ↔ *a

- a[1] ↔ *(a+1)

- a[n] ↔ *(a+n)

3. 数组做函数参数时,底层会退化为对应类型指针。

小结

1. 预处理是编译第一阶段,核心完成文本替换,宏、头文件、条件编译是开发高频工具,头文件保护宏是工程必备规范;

2. gcc四阶段编译命令需熟记,可单独生成.i/.s/.o中间文件用于调试底层代码;

3. 指针本质是内存地址, & 取地址、 * 解引用是基础操作,算数偏移遵循基类型字节大小;

4. 传地址调用是指针核心应用:实现函数修改变量、多返回值、数组批量操作,是测井嵌入式、Linux C课程设计的高频考点;

5. 数组名等价首元素指针,下标与指针写法可以互相转换,是遍历数组的两种实现方式。