C 语言中的预处理器
C 预处理器不是编译器的一部分,而是编译过程中的一个独立步骤。简单来说,C 预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行必要的预处理。我们将 C 预处理器称为 CPP。
在 C 语言编程中,预处理是 C 代码编译的第一步。它发生在标记化步骤之前。预处理器的一个重要功能是包含包含程序中使用的库函数的头文件。C 语言中的预处理器还定义常量并扩展宏。
C 语言中的预处理器语句称为指令。程序的预处理器部分始终位于 C 代码的顶部。每个预处理器语句都以井号 (#) 开头。
C 语言中的预处理器指令
下表列出了所有重要的预处理器指令 -
| 指令 | 描述 |
|---|---|
| # Define | 替换预处理器宏。 |
| # Include | 插入来自另一个文件的特定头文件。 |
| # Undef | 取消定义预处理器宏。 |
| #ifdef | 如果此宏已定义,则返回 true。 |
| #ifndef | 如果此宏未定义,则返回 true。 |
| #if | 测试编译时条件是否为真。 |
| #else | #if 的替代方案。 |
| #elif | #else 和 #if 合二为一语句。 |
| #endif | 结束预处理器条件。 |
| #error | 在 stderr 上打印错误消息。 |
| #pragma | 使用标准化方法向编译器发出特殊命令。 |
预处理器示例
分析以下示例以理解各种指令。
此 #define 指令指示 CPP 将 MAX_ARRAY_LENGTH 的实例替换为 20。使用 #define 常量可提高可读性。
#define MAX_ARRAY_LENGTH 20
以下指令指示 CPP 从系统库中获取"stdio.h"并将文本添加到当前源文件中。下一行指示 CPP 从本地目录中获取"myheader.h"并将内容添加到当前源文件中。
#include <stdio.h> #include "myheader.h"
现在,请看一下以下 #define 和 #undef 指令。它们指示 CPP 取消定义现有的 FILE_SIZE,并将其定义为 42。
#undef FILE_SIZE #define FILE_SIZE 42
以下指令指示 CPP 仅在 MESSAGE 尚未定义时定义 MESSAGE。
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
如果定义了 DEBUG,则以下指令告诉 CPP 处理所附的语句。
#ifdef DEBUG /* Your debugging statements here */ #endif
如果您在编译时将 -DDEBUG 标志传递给 gcc 编译器,这将非常有用。这将定义 DEBUG,以便您可以在编译过程中动态地打开或关闭调试功能。
C 语言中的预定义宏
ANSI C 定义了许多宏。虽然每个宏都可以在编程中使用,但不应直接修改预定义的宏。
| 宏 | 描述 |
|---|---|
| __DATE__ | 以字符形式表示的当前日期,格式为"MMM DD YYYY"。 |
| __TIME__ | 以字符形式表示的当前时间,格式为"HH:MM:SS"。 |
| __FILE__ | 包含当前文件名的字符串字面量。 |
| __LINE__ | 包含当前行号的十进制常量。 |
| __STDC__ | 当编译器符合 ANSI 标准时,定义为 1。 |
示例
让我们尝试以下示例 -
#include <stdio.h>
int main(){
printf("File: %s
", __FILE__ );
printf("Date: %s
", __DATE__ );
printf("Time: %s
", __TIME__ );
printf("Line: %d
", __LINE__ );
printf("ANSI: %d
", __STDC__ );
}
输出
运行此代码时,将产生以下输出 -
File: main.c Date: Mar 6 2024 Time: 13:32:30 Line: 8 ANSI: 1
预处理器运算符
C 预处理器提供以下运算符来帮助创建宏 -
示例:C 中的宏延续运算符 (\)
宏通常限制在一行中。宏延续运算符 (\) 用于延续过长而无法在一行中显示的宏。请看以下示例 -
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!
")
int main() {
message_for(Ram, Raju);
}
输出
运行此代码时,将产生以下输出 -
Ram and Raju: We love you!
示例:C 语言中的字符串化运算符 (#)
字符串化运算符 (#),也称为数字符号运算符,在宏定义中使用时,可将宏参数转换为字符串常量。
字符串化运算符只能在具有指定参数或参数列表的宏中使用。例如 -
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!
")
int main() {
message_for(Carole, Debra);
return 0;
}
输出
运行代码并检查其输出 −
Carole and Debra: We love you!
示例:C 语言中的标记粘贴运算符 (##)
宏定义中的标记粘贴运算符 (##) 可合并两个参数。它允许将宏定义中的两个独立标记合并为一个标记。例如 -
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main() {
int token34 = 40;
tokenpaster(34);
return 0;
}
输出
运行此代码时,将产生以下输出 -
token34 = 40
示例:C 语言中的 Defined() 运算符
预处理器 Defined 运算符用于常量表达式中,用于判断标识符是否已使用 #define 定义。如果指定的标识符已定义,则值为 True(非零)。如果符号未定义,则值为 false(零)。
以下示例展示了如何在 C 程序中使用 defined 运算符 -
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main() {
printf("Here is the message: %s
", MESSAGE);
return 0;
}
输出
运行代码并检查其输出 −
Here is the message: You wish!
C 语言中的参数化宏
CPP 的强大功能之一是能够使用参数化宏模拟函数。例如,我们可能有一些代码用于计算数字的平方,如下所示 -
int square(int x) {
return x * x;
}
我们可以使用宏重写上述代码,如下所示 -
#define square(x) ((x) * (x))
带有参数的宏必须先使用 #define 指令定义,然后才能使用。参数列表括在括号中,并且必须紧跟在宏名称之后。宏名和左括号之间不允许有空格。
示例
以下示例演示了如何在 C 中使用参数化宏 -
#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main() {
printf("Max between 20 and 10 is %d
", MAX(10, 20));
return 0;
}
输出
运行此代码时,将产生以下输出 -
Max between 20 and 10 is 20

