C预处理器在程序运行之前查看程序。
根据程序中的预处理器指令,把符号缩写替换成其他内容。
它的工作基本上是把一些文本转换成另一些文本。
明示常量:#define
#define最显而易见的功能就是宏替换。 宏定义的组成:
示例: 常用#define可以这样替换数字、替换为另一个宏、声明数组大小、替换表达式以及字符串等这些
#include<stdio.h>
#define SIZE 10
#define OVERSIZE SIZE * SIZE
#define PAB printf("a = %d b = %d\n", a, b)
#define ADDRESS "I live in Xi'an.\n"
int main(void)
{
int a = SIZE;
int b = OVERSIZE;
int ar[SIZE] = {};
PAB;
printf("%s\n", ADDRESS);
printf(ADDRESS);
return 0;
}
运行结果
在#define中使用参数
在#define中使用参数可以创建外形和作用与函数类似的类函数宏。 类函数宏示例:
程序示例:
#include<stdio.h>
#define SQUARE(X) X * X
#define SQUARE2(Y) (Y) * (Y)
#define PB printf("b = %d\n", b)
#define PC printf("c = %d\n", c)
#define TIME(T) printf("\nNO. %d print:\n", T)
int main(void)
{
int a = 3;
int b = SQUARE(a);
int c = SQUARE2(a);
TIME(1);
PB;
PC;
b = SQUARE(a + 1);
c = SQUARE2(a + 1);
TIME(2);
PB;
PC;
return 0;
}
运行结果
问题 为什么第二次打印的结果不同呢? 原因就是编写的宏替换体不同 当我把数字3 传进SQUARE(X) 时,会被替换成 3×3(这里拿×代替*,星号打的多了会出现看不到的问题); 传进SQUARE2(Y)时,被替换成 (3) × (3); 所以在第二次中: 把 a + 1即 3 + 1写进SQUARE(X)时,被替换成 3 + 1×3 + 1,运算结果为7 而到了SQUARE2(Y)时,被替换成 (3+1)×(3+1),运算结果为16。
用宏参数创建字符串:#运算符
C允许在字符串中包含宏参数。 在类函数宏的替换体中,#作为一个预处理运算符,可以把记号转换为字符串。 程序示例:
#include<stdio.h>
#define PRINT(x) printf("The square of " #x " is %d\n", ((x)*(x)))
int main(void)
{
int a = 3;
PRINT(a);
PRINT(a + 1);
return 0;
}
运行结果
预处理器粘合剂:##运算符
若有:
#define XNAME(n) x ## n
宏XNAME(n)展开为 x4. 程序示例:
#include<stdio.h>
#define XNAME(n) x ## n
#define PRINT(n) printf("x" #n " = %d\n", x ## n)
int main(void)
{
int XNAME(1) = 5;
PRINT(1);
return 0;
}
运行结果
文件包含:#include
当预处理器发现#include指令时,会查看后面的文件名,并把文件的内容包含到当前文件中,即替换源文件中的#include指令。
#include指令有两种形式,例如:
#include<stdio.h> //查找系统目录
#include"myhead.h" //查找当前工作目录
使用头文件
我们在编写程序时要养成把头文件和源文件放在不同文件中。
头文件最常用形式:
- 明示常量——例如stdio.h中的EOF 、NULL等
- 宏常量——最常用的即#define等
- 函数声明——比如一个求和函数 int Add(int x, int y);
- 结构体模板——自己创建的结构体
- 类型定义——typedef 等
比如一个单链表的头文件:
#pragma once
typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node* next;
}Node, *PNode;
void Init_List(Node * plist);
bool Insert_Head(PNode plist, ElemType val);
bool Insert_Tail(PNode plist, ElemType val);
bool Insert_Pos(PNode plist, int pos, ElemType val);
bool Del_Pos(PNode plist, int pos);
bool Del_Val(PNode plist, ElemType val);
struct Node* Search(PNode plist, ElemType val);
Node* Get_Prior(PNode plist, ElemType val);
Node* Get_Next(PNode plist, ElemType val);
bool IsEmpty(PNode plist);
int Get_length(PNode plist);
void Clear(PNode plist);
void Destroy(PNode plist);
void Destroy2(PNode plist);
void Show(PNode plist);
#pragma once 指定该文件在编译源代码文件时仅由编译器打开一次。
#undef
#undef指令用于取消已定义的#define指令。 若有: #define SIZE 10 则 #undef SIZE 会移除上面的定义。
如果想使用一个名称,又不确定之前是否已经用过,为安全起见,可以使用 #undef指令取消改名字的定义。
条件编译
#ifdef、#else和#endif 用法:
#ifdef PRINT
#include"myhead.h"
#define SIZE 5
#else
#include"head.h"
#define SIZE 10
#endif
#ifndef
用法和#ifdef相似,可以和 #else 和 #endif一起使用,但逻辑和#ifdef相反。
#ifndef用于判断后面的标识符是否是未定义的。 例如:
#ifndef SIZE
#define SIZE 10
#endif
|