📅  最后修改于: 2020-12-19 05:32:12             🧑  作者: Mango
C预处理程序不是编译器的一部分,而是编译过程中的一个单独步骤。简单来说,C预处理器只是一种文本替换工具,它指示编译器在实际编译之前进行所需的预处理。我们将C预处理器称为CPP。
所有预处理器命令均以井号(#)开头。它必须是第一个非空白字符,并且为了便于阅读,预处理器指令应该在第一列中开始。以下部分列出了所有重要的预处理器指令-
Sr.No. | Directive & Description |
---|---|
1 |
#define Substitutes a preprocessor macro. |
2 |
#include Inserts a particular header from another file. |
3 |
#undef Undefines a preprocessor macro. |
4 |
#ifdef Returns true if this macro is defined. |
5 |
#ifndef Returns true if this macro is not defined. |
6 |
#if Tests if a compile time condition is true. |
7 |
#else The alternative for #if. |
8 |
#elif #else and #if in one statement. |
9 |
#endif Ends preprocessor conditional. |
10 |
#error Prints error message on stderr. |
11 |
#pragma Issues special commands to the compiler, using a standardized method. |
分析以下示例以了解各种指令。
#define MAX_ARRAY_LENGTH 20
该指令告诉CPP用20替换MAX_ARRAY_LENGTH的实例。对常量使用#define以提高可读性。
#include
#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 & Description |
---|---|
1 |
__DATE__ The current date as a character literal in “MMM DD YYYY” format. |
2 |
__TIME__ The current time as a character literal in “HH:MM:SS” format. |
3 |
__FILE__ This contains the current filename as a string literal. |
4 |
__LINE__ This contains the current line number as a decimal constant. |
5 |
__STDC__ Defined as 1 when the compiler complies with the ANSI standard. |
让我们尝试以下示例-
#include
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 2012
Time :03:36:24
Line :8
ANSI :1
C预处理程序提供以下运算符以帮助创建宏-
宏通常限于一行。宏延续运算符(\)用于延续对于单行来说太长的宏。例如-
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
字符串化或数字符号运算符(’#’)在宏定义中使用时,会将宏参数转换为字符串常量。该运算符只能在具有指定参数或参数列表的宏中使用。例如-
#include
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
编译并执行上述代码后,将产生以下结果-
Carole and Debra: We love you!
宏定义中的令牌粘贴运算符(##)组合了两个参数。它允许将宏定义中的两个单独的标记合并为一个标记。例如-
#include
#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);
此示例显示了将token ## n连接到token34的情况,这里我们同时使用了stringize和token- pasting。
在常量表达式中使用预处理器定义的运算符,以确定是否使用#define定义了标识符。如果定义了指定的标识符,则该值为true(非零)。如果未定义符号,则该值为false(零)。定义的运算符指定如下-
#include
#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
#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