C语言day11 预处理
define 宏名 宏值用宏名代替宏值(文本原样替换)方便修改,一改全改提高代码可读性auto:栈上自动存储(默认)static:静态区存储,延长生命周期或限定作用域register:建议存储在寄存器extern:声明外部变量/函数。
·
一、存储类别关键字
1. auto(自动存储)
- 数据存储在栈上
- 自动申请、自动释放
2. static(静态存储)
- 数据存储在静态区(全局区)
- 生命周期为整个程序运行期间
静态区变量初始化规则:
- 只能用常量初始化,不能用变量初始化
- 只需要初始化一次
static修饰局部变量:
- 值具有继承性(保持上次的值)
- 延长了局部变量的生命周期
static修饰全局变量/函数:
- 限定作用域为本文件
- 其他文件通过extern也无法引用
- 作用:保护数据,防止命名冲突
3. extern(外部声明)
- 声明所用的变量或函数是在外部定义的
- 作用:扩展标识符的作用域
- 可以让全局变量在整个工程中使用
4. register(寄存器)
- 建议编译器将变量存储在寄存器中(仅建议)
- 不能对register变量取地址(&运算)
- 用于频繁访问的变量,提高效率
计算机存储体系(按速度排序):
CPU → 寄存器 → Cache(高速缓存)→ 内存 → 硬盘
容量:小 ←→ 大
速度:快 ←→ 慢
价格:贵 ←→ 便宜
二、编译过程
GCC编译的4个阶段
hello.c → [预处理] → [编译] → [汇编] → [链接] → a.out
- 预处理:处理预处理命令,生成纯C语言文件
- 编译:将C代码编译为汇编代码
- 汇编:将汇编代码翻译为机器指令
- 链接:将相关代码链接成最终可执行文件
三、预处理命令
所有预处理命令都以 # 开头
1. 宏定义
(1)普通宏(符号常量)
#define PI 3.14
#define 宏名 宏值
作用:
- 用宏名代替宏值(文本原样替换)
好处:
- 方便修改,一改全改
- 提高代码可读性
(2)带参宏
#define S(r) (PI*(r)*(r))
#define 宏名(参数表) 宏值
使用示例:
printf("S = %f\n", S(2)); // 展开为:PI*2*2
注意事项:
- 带参宏形式像函数,但不是函数
- 避免副作用:能加括号的地方都加上
- 宏名约定用大写(与变量、函数区分)
- 宏定义这一行不要写分号
- 宏的作用域:从定义处到文件末尾(或#undef处)
- 使用
#undef 宏名可终止宏的作用
带参宏 vs 函数:
| 对比项 | 带参宏 | 函数 |
|---|---|---|
| 处理阶段 | 预处理阶段 | 编译阶段 |
| 参数类型 | 无类型 | 有类型检查 |
| 代码体积 | 可能变大(每次展开) | 只有一份代码 |
| 适用场景 | 简短代码(≤5行) | 复杂逻辑 |
续行符:
- 宏定义结束标志是换行符
- 使用
\可以续行
2. 文件包含
#include <stdio.h> // 系统头文件,在系统路径查找
#include "myhead.h" // 自定义头文件,先在当前目录查找
区别:
#include <>:直接到系统路径查找#include "":先查找当前目录,找不到再查系统路径
作用:
- 将指定文件的内容替换到当前位置
3. 条件编译
选择性地编译某些代码
形式1:#ifdef
#ifdef 标识符
程序段1
#else
程序段2
#endif
含义:如果定义了标识符,编译程序段1,否则编译程序段2
形式2:#ifndef
#ifndef 标识符
程序段1
#else
程序段2
#endif
含义:如果没有定义标识符,编译程序段1,否则编译程序段2
形式3:#if
#if 表达式
程序段1
#else
程序段2
#endif
含义:如果表达式为真,编译程序段1,否则编译程序段2
实用技巧:
#if 0
// 这段代码不会被编译(相当于注释掉大段代码)
#endif
四、知识点小结
重要概念
- 标识符作用域和可见性
- 局部变量 vs 全局变量
- 变量的生命周期
存储类别关键字总结
auto:栈上自动存储(默认)static:静态区存储,延长生命周期或限定作用域register:建议存储在寄存器extern:声明外部变量/函数
预处理核心
- 文本原样替换
- 提高编译效率和代码可维护性
作业






更多推荐


所有评论(0)