C语言——C预处理器


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; //转换成 int x1 = 5;

	PRINT(1); //转换成 printf("x1 = %d\n", x1);

	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);//Node * == PNode

//头插
bool Insert_Head(PNode plist, ElemType val);

//尾插
bool Insert_Tail(PNode plist, ElemType val);

//按位置插入  pos  
bool Insert_Pos(PNode plist, int pos, ElemType val);

//按位置删除 pos 
bool Del_Pos(PNode plist, int pos);

//按值删除 遇到值为val的第一个有效节点 删除掉 释放其内存
bool Del_Val(PNode plist, ElemType val);

//查找search 查找值我val的第一个节点,返回其地址
struct Node* Search(PNode plist, ElemType val);

//寻找值为val的节点的前驱
Node* Get_Prior(PNode plist, ElemType val);

//寻找值为val的节点的后继
Node* Get_Next(PNode plist, ElemType val);

//判空
bool IsEmpty(PNode plist);

//判满
//bool IsFull(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	//如果定义了PRINT,则执行下面的指令
#include"myhead.h"
#define SIZE 5
#else		//如果没有用#define定义PRINT,则执行下面命令
#include"head.h"
#define SIZE 10
#endif

#ifndef

用法和#ifdef相似,可以和 #else 和 #endif一起使用,但逻辑和#ifdef相反。

#ifndef用于判断后面的标识符是否是未定义的。
例如:

#ifndef SIZE
#define SIZE 10
#endif
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值