当前位置: 首页 > article >正文

重回C语言之老兵重装上阵(十三)C 预处理器

C 语言预处理器


C 预处理器(Preprocessor)是编译过程中的一个重要阶段,它在编译器实际编译代码之前,对源代码进行文本替换和处理。预处理器的主要任务是处理指令以生成最终的代码,并为编译器提供准备工作。常见的预处理指令以 # 开头。

1. 宏定义 (#define)

#define 用来定义常量或宏,宏是由预处理器在编译时进行文本替换的。

示例:
#define PI 3.14159

此后,源代码中所有出现 PI 的地方都会被替换为 3.14159

宏函数:

可以使用 #define 定义宏函数,这样就可以进行更复杂的文本替换。

#define SQUARE(x) ((x) * (x))

此后,SQUARE(5) 会被替换成 ((5) * (5))


2. 条件编译 (#if, #ifdef, #ifndef, #else, #endif)

条件编译允许在编译过程中根据某些条件来包含或排除代码块。

示例:
#define DEBUG

#ifdef DEBUG
    printf("Debugging mode is enabled.\n");
#endif

如果定义了 DEBUG 宏,则会执行 printf 语句,否则会跳过。

  • #if:根据表达式的值判断是否编译某部分代码。
  • #ifdef:如果宏已定义,则编译相应部分。
  • #ifndef:如果宏没有定义,则编译相应部分。
  • #else:如果前面的条件不成立,则编译 #else 部分。
  • #endif:结束条件编译。

3. 文件包含 (#include)

#include 用于包含头文件,可以是标准库头文件,也可以是用户自定义的头文件。

示例:
#include <stdio.h>   // 包含标准库头文件
#include "myheader.h" // 包含自定义头文件
  • <filename>:用于包含标准库文件。
  • "filename":用于包含自定义的头文件,通常是相对路径。

4. 文件宏 (#line, #file)

这些指令用于改变源文件的行号和文件名,通常用于调试或生成错误信息时提供有用的调试信息。

示例:
#line 100 "newfile.c"

这会告诉编译器当前的文件为 newfile.c,并且当前行号为 100。


5. 预定义宏

C 预处理器提供了一些预定义的宏,它们在编译时自动存在。

  • __DATE__:表示当前日期,格式为 “Mmm dd yyyy”。
  • __TIME__:表示当前时间,格式为 “hh:mm:ss”。
  • __FILE__:表示当前源代码文件的路径。
  • __LINE__:表示当前源代码文件的行号。
示例:
printf("File: %s, Line: %d\n", __FILE__, __LINE__);

输出将会显示源文件名和当前行号。


6. 取消定义 (#undef)

#undef 用于取消已定义的宏。

示例:
#define PI 3.14159
#undef PI

这样,PI 宏就不再有效,如果再使用 PI,编译器会报错。


7. 代码连接 (#pragma)

#pragma 用于向编译器提供指令,它不是标准的一部分,不同的编译器可能会有不同的实现。常见的用途是控制编译警告或优化设置。

示例:
#pragma once

#pragma once 是一种防止头文件重复包含的方式,效果与 #ifndef#define#endif 类似。


8. 错误和警告处理 (#error, #warning)

预处理器指令 #error#warning 可以用来生成编译时错误或警告信息。

示例:
#error "This is an error message"

此时,编译器会报出一个错误,错误信息为 "This is an error message"


9. 预处理器的其他功能

文件合并

C 预处理器还支持文件合并,通常是在宏中使用 ## 连接两个标记。

#define CONCAT(a, b) a##b
int CONCAT(my, Var) = 5; // 变为 int myVar = 5;
字符串化

# 用于字符串化,它会将宏参数转换为字符串字面量。

#define TO_STRING(x) #x
printf(TO_STRING(Hello World)); // 输出 "Hello World"

http://www.kler.cn/a/520849.html

相关文章:

  • 如何实现滑动删除功能
  • .NET Core 中依赖注入的使用
  • C# 添加、替换、提取、或删除Excel中的图片
  • PCIE模式配置
  • JS中对数组的操作哪些会改变原数组哪些不会?今天你一定要记下!
  • LeetCode 0045.跳跃游戏 II:贪心(柳暗花明又一村)
  • 2025美赛美国大学生数学建模竞赛A题完整思路分析论文(43页)(含模型、可运行代码和运行结果)
  • C# 探秘:PDFiumCore 开启PDF读取魔法之旅
  • Apache Flink 概述学习笔记
  • java基础-容器
  • ORACLE-主备备-Failover
  • 每日 Java 面试题分享【第 12 天】
  • Ansible自动化运维实战--yaml的使用和配置(7/8)
  • 企业知识管理平台的对比分析与优化策略探讨
  • 蓝桥杯模拟算法:蛇形方阵
  • cloc下载和使用
  • C#新语法
  • ES filter和post_filter的区别
  • IDEA全局搜索Ctrl+Shift+F失效
  • vim的特殊模式-可视化模式
  • 超市数字化落地:RWA + 智能体赋能实体零售数字化
  • 2025美赛MCM数学建模A题:《石头台阶的“记忆”:如何用数学揭开历史的足迹》(全网最全思路+模型)
  • Ubuntu Server 安装 XFCE4桌面
  • leetcode152-乘积最大的子数组
  • Forsaken喜欢数论(线性筛)
  • H266/VVC 量化编码中量化矩阵 QM 技术