C预处理器不是编译器的一部分,而是编译过程中的一个单独步骤。简单来说,C预处理器只是一种文本替换工具,它指示编译器在实际编译之前进行所需的预处理,我们将C预处理器称为CPP。
所有预处理器命令均以井号(#)开头。它必须是第一个非空白字符,并且为了可读性,预处理器指令应在第一列中开始。以下部分列出了所有重要的预处理器指令-
Sr.No. | Directive & 描述 |
---|---|
1 | #define 替代预处理器宏。 |
2 | #include 从另一个文件插入特定的标头。 链接:https://www.learnfk.comhttps://www.learnfk.com/c-programming/c-preprocessors.html 来源:LearnFk无涯教程网 |
3 | #undef 未定义预处理器宏。 |
4 | #ifdef 如果定义了此宏,则返回true。 |
5 | #ifndef 如果未定义此宏,则返回true。 |
6 | #if 测试编译时间条件是否为真。 |
7 | #else #if的替代方法。 |
8 | #elif #else和#if在一条语句中。 |
9 | #endif 有条件地结束预处理程序。 |
10 | #error 在stderr上显示错误消息。 |
11 | #pragma 使用标准化方法向编译器发出特殊命令。 |
分析以下示例以了解各种指令。
#define MAX_ARRAY_LENGTH 20
该指令告诉CPP用20替换MAX_ARRAY_LENGTH的。对常量使用 #define 可以提高可读性。
#include <stdio.h> #include "myheader.h"
这些指令告诉CPP从系统库获取stdio.h并将文本添加到当前源文件中,下一行告诉CPP从本地目录获取 myheader.h 并将内容添加到当前源文件中。
#undef FILE_SIZE #define FILE_SIZE 42
它告诉CPP取消定义现有的FILE_SIZE并将其定义为42。
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
它告诉CPP仅在尚未定义MESSAGE时定义MESSAGE。
#ifdef DEBUG /* Your debugging statements here */ #endif
如果定义了DEBUG,它将告诉CPP处理包含的语句,如果在编译时将 -DDEBUG 标志传递给gcc编译器,这将很有用。这将定义DEBUG,因此您可以在编译过程中即时打开和关闭调试。
ANSI C定义了许多宏。尽管可以在编程中使用每个宏,但是不应直接修改预定义的宏。
Sr.No. | Macro & 描述 |
---|---|
1 | __ DATE __ 以" MMM DD YYYY"格式的字符文字形式的当前日期。 |
2 | __ TIME __ 当前时间,以" HH:MM:SS"格式的字符文字显示。 |
3 | __ FILE __ 它包含当前文件名作为字符串文字。 |
4 | __ LINE __ 它包含当前行号作为十进制常数。 |
5 | __ STDC __ 编译器符合ANSI标准时定义为1。 |
让我们尝试以下示例-
#include <stdio.h> int main() { printf("File :%s\n", __FILE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ ); printf("Line :%d\n", __LINE__ ); printf("ANSI :%d\n", __STDC__ ); }
编译并执行文件 test.c 中的上述代码后,将产生以下输出-
File :test.c Date :Jun 2 2021 Time :03:36:24 Line :8 ANSI :1
C预处理器提供以下运算符以帮助创建宏-
宏通常限于一行
#define message_for(a, b)\ printf(#a " and " #b ": We love you!\n")
字符串化或数字符号运算符('#')在宏定义中使用时,会将宏参数转换为字符串常量,该运算符只能在具有指定参数或参数列表的宏中使用。如-
#include <stdio.h> #define message_for(a, b)\ printf(#a " and " #b ": We love you!\n") int main(void) { message_for(Learnfk, Toolfk); return 0; }
编译并执行上述代码后,将产生以下输出-
Learnfk and Toolfk: We love you!
宏定义中的token-pasting运算符(##)组合了两个参数,它允许将宏定义中的两个单独的标签合并为一个标签。如-
#include <stdio.h> #define tokenpaster(n) printf ("token" #n "=%d", token##n) int main(void) { int token34=40; tokenpaster(34); return 0; }
编译并执行上述代码后,将产生以下输出-
token34=40
发生这种情况是因为此示例导致了预处理器的以下实际输出-
printf ("token34=%d", token34);
在常量表达式中使用预处理器 defined 来确定是否使用#define定义了标识符,如果定义了指定的标识符,则该值为true(非零)。如果未定义符号,则该值为false(零)。定义的运算符指定如下-
#include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { printf("Here is the message: %s\n", MESSAGE); return 0; }
编译并执行上述代码后,将产生以下输出-
Here is the message: You wish!
CPP的强大函数之一是能够使用参数化宏模拟函数,如我们可能有一些代码可以对数字平方,如下所示:
int square(int x) { return x * x; }
我们可以使用宏如下重写代码:
#define square(x) ((x) * (x))
必须先使用#define指令定义带有参数的宏,然后才能使用。 参数列表用括号括起来,并且必须紧随宏名称之后,宏名称和右括号之间不允许有空格。
#include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf("Max between 20 and 10 is %d\n", MAX(10, 20)); return 0; }
编译并执行上述代码后,将产生以下输出-
Max between 20 and 10 is 20
祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)
Spring Cloud 微服务项目实战 -〔姚秋辰(姚半仙)〕