C预处理器不是编译器的一部分,而是编译过程中的一个单独步骤.简单来说,C预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行必要的预处理.我们将C预处理器称为CPP.
所有预处理器命令都以井号(#)开头.它必须是第一个非空白字符,并且为了便于阅读,预处理程序指令应该从第一列开始.以下部分列出了所有重要的预处理程序指令 :
Sr.No. | 指令&说明 |
---|---|
1 | #define 替换预处理器宏. |
2 | #include 从其他文件插入特定标头. |
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 __ 当定义为1时编译器符合ANSI标准. |
让我们尝试以下示例 :
#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 2012 Time :03:36:24 Line :8 ANSI :1
C预处理器提供以下运算符来帮助创建宏;
宏通常仅限于一行.宏继续运算符(\)用于继续对于单行来说太长的宏.例如 :
#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")
字符串大小或数字符号operator('#')在宏定义中使用时,将宏参数转换为字符串常量.此运算符只能在具有指定参数或参数列表的宏中使用.例如 :
#include <stdio.h> #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 <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);
此示例显示令牌## n到token34的串联,这里我们使用了 stringize 和令牌 - 粘贴.
预处理器已定义运算符用于常量表达式确定是否使用#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))
必须使用
#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