第28篇 预处理详解

发布时间:2026/10/8 8:38:13
第28篇 预处理详解 目录一、预定义符号与#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修改行号信息

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询