目录一、预定义符号与#define常量定义1. 预定义符号2. #define定义常量⚙️ 二、宏定义机制与副作用1. 宏定义语法2. 宏参数副作用3. 宏替换规则4. 宏与函数对比5. #和##运算符️ 三、命名约定与#undef指令1. 命名约定2. #undef指令️ 四、命令行定义与条件编译1. 命令行定义2. 条件编译 五、头文件包含与防重复包含1. 包含方式2. 嵌套包含问题 六、其他预处理指令一、预定义符号与#define常量定义1. 预定义符号C语言内置了若干预定义符号在预处理阶段直接处理无需定义即可使用__FILE__当前编译的源文件名__LINE__当前行号__DATE__文件编译日期__TIME__文件编译时间__STDC__若编译器遵循ANSI C标准值为1否则未定义2. #define定义常量基本语法#define name stuff示例#define MAX 1000定义数值常量#define reg register为关键字创建简短别名#define do_forever for(;;)用形象符号替换实现#define DEBUG_PRINT printf(file:%s\tline:%d\tdate:%s\ttime:%s\n, __FILE__, __LINE__, __DATE__, __TIME__)多行定义需使用反斜杠\续行注意事项定义标识符时不建议在末尾加分号否则可能导致语法错误。例如#define MAX 1000; // 错误示例 if (condition) max MAX; // 替换后变成max 1000;;导致if和else之间出现两条语句 else max 0;二、宏定义机制与副作用1. 宏定义语法声明方式#define name(parament-list) stuff注意参数列表的左括号必须与宏名紧邻否则会被解释为stuff的一部分。示例#define SQUARE(x) x * x陷阱与修复问题1SQUARE(a 1)替换后变成a 1 * a 1运算顺序错误。修复#define SQUARE(x) (x) * (x)问题2#define DOUBLE(x) (x) (x)在10 * DOUBLE(a)中替换为10 * (a) (a)乘法优先级导致错误。修复#define DOUBLE(x) ((x) (x))原则数值表达式宏定义应在参数和整体表达式两边都加括号避免运算符优先级问题。2. 宏参数副作用副作用定义表达式求值时产生的永久性效果如x。危险示例#define MAX(a, b) ((a) (b) ? (a) : (b)) z MAX(x, y); // 替换后((x) (y) ? (x) : (y)) // 结果x和y可能被多次自增导致不可预测结果3. 宏替换规则调用宏时先检查参数是否包含#define定义的符号若有则先替换。替换文本插入原位置宏参数被值替换。再次扫描结果文件重复上述过程。注意宏参数和定义中可包含其他宏但宏不能递归字符串常量内容不被搜索。4. 宏与函数对比属性#define宏函数代码长度每次使用都插入代码程序长度增长代码只出现一次调用同一份代码执行速度更快无调用开销有调用和返回开销稍慢操作符优先级需加括号避免优先级问题参数求值一次结果可预测副作用参数多次计算可能导致不可预料结果参数求值一次结果可控参数类型类型无关适用于任何合法类型参数类型相关需声明特定类型调试不方便调试可逐语句调试递归不能递归可递归宏的特殊能力参数可出现类型如#define MALLOC(num, type) (type*)malloc(num * sizeof(type))函数无法做到。5. #和##运算符#运算符将宏参数转换为字符串字面量字符串化。#define PRINT(n) printf(the value of #n is %d, n) PRINT(a); // 替换为printf(the value of a is %d, a)##运算符连接两边符号创建新标识符记号粘合。#define GENERIC_MAX(type) type type##_max(type x, type y) { return (xy?x:y); } GENERIC_MAX(int) // 生成int int_max(int x, int y) { ... }三、命名约定与#undef指令1. 命名约定宏名全部大写如MAX_SIZE函数名不全大写如getMax2. #undef指令作用移除已定义的宏。语法#undef NAME用途重新定义宏前需先移除旧定义。四、命令行定义与条件编译1. 命令行定义功能编译时在命令行定义符号用于生成程序不同版本。示例gcc -D ARRAY_SIZE10 program.cLinux环境2. 条件编译用途选择性编译代码如调试代码。常见指令#if 常量表达式 ... #endif#if ... #elif ... #else ... #endif多分支#ifdef symbol/#ifndef symbol判断是否定义嵌套指令#if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif五、头文件包含与防重复包含1. 包含方式本地文件包含#include filename查找策略先在源文件所在目录查找未找到再去标准路径。库文件包含#include filename.h查找策略直接去标准路径查找。标准路径Linux/usr/includeVSC:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include2. 嵌套包含问题问题头文件被重复包含会导致内容被多次拷贝增加编译压力。解决方案条件编译防重#ifndef __TEST_H__ #define __TEST_H__ // 头文件内容 #endif#pragma once避免重复引入推荐。六、其他预处理指令#error生成错误信息#pragma设置编译器状态如#pragma pack()用于结构体对齐#line修改行号信息