预处理详解(其二)

目录

前言:

一、库文件包含:#include

1、尖括号 <>

2、双引号""

注意:

二、#define的替换:

#define 和 typedef:

1、处理时间:

2、 作用域不同:

相同点:

 #undef指令:

三、条件编译:

#if:

#endif:

 #elif:

注意:

#ifdef:

#ifndef:

四、defined函数:

五、解决头文件重复引入的问题:

1、每个文件的开头用#ifndef:

 2、#pragma once 指令

五、总结:


前言:

        这篇主要讲#undef、#if、#elif、#endif、#ifdef、#ifndef等

​​​​​参考资料 

预处理命令
在接触#if、#undef这类预处理指令前,我们接触过#define、#include等预处理命令,它作用就是在编译和链接之前,对源文件进行一些文本方面的操作,比如文本替换、文件包含、删除部分代码等,这个过程叫做预处理(在编译开始之前会对源文件进行简单加工)

一、库文件包含:#include

1、尖括号 <>

#include<stdio.h>

 直接在系统路径(标准路径)查找(相当于直接去标准库

2、双引号""

#include"stdio.h"

编译器会先在当前目录下(源文件所在目录下)查找头文件,如果没有找到,再到系统路径(标准路径)下查找(先找自己的库,没有再去标准库

注意:

1、一个 #include 命令只能包含一个头文件

2、同一个头文件可以被多次引入,多次引入的效果和一次引入的效果相同,因为头文件在代码层面有防止重复引入的机制

3、头文件包含允许嵌套

(头文件只能包含变量和函数声明不能包含定义,否则在多次引入时会引起重复定义错误) 

4、替换方式:在预处理阶段会删除这条指令,将包含文件的内容替换该源文件中,如果重复包含次数过多,会导致编译压力比较大(代码量剧增),为了解决这个问题用到了条件编译

二、#define的替换:

并不是所有的#define都能进行替换

#define 和 typedef:

1、处理时间:

#define(宏定义)----由预处理器来处理

typedef----在编译阶段编译器处理

2、 作用域不同:

#define——从定义开始整个文件末尾(不考虑在函数内部还是外部,没有全局与局部区分

typedef——函数内:离开该函数失去定义(局部)

                   函数外:从定义开始到整个文件末尾(全局)

相同点:

         不管是typedef还是define,其作用域都不会扩展到别的文件,即使是同一个程序的不同文件,也不能互相使用;


 #undef指令:

移除宏定义,相当于给一个宏定义,变成了有界函数;当然了下面要用这个名字重新定义,就需要将旧的移除

#undef  宏名

如下,MAX的上界和下界,不在这个范围,使用不了这个宏

三、条件编译:

#if:

和if……else 用法类似,else if#elif,但是if()  括号的表达式无限制,#if 的后面只能是整形表达式常量 不能是变量!!!!!!

#if 整型常量表达式1(为真执行)
    程序段1
#elif 整型常量表达式2(为真执行)
    程序段2
#else
    程序段3
#endif

 下面打印的else的printf,整形常量表达式不是就是只能写数字  因为 #define可以定义常量,所以可以用宏,可以是表达式 可以进行判断 如:MAX<10  只要保证是常量表达式即可

#define MAX 0
int main()
{
#if MAX
	printf("有最大值");
#else
	printf("没有最大值");
#endif
	return 0;
}

#endif:

这个指令和那个#undef有点类似哈,作为条件编译结束的标志

你也可以理解为上限,控制了范围,用条件编译就需要它


 #elif:

类似与多个条件判断时else if的用法

#define MAX 10
int main()
{
#if MAX==0
	printf("MAX未被定义");
#elif MAX==10
	printf("MAX被定义");
#endif
	return 0;
}

注意:

还是得说一遍,只能是常量表达式,变量是不行的,千万不要用变量做判断条件

#ifdef:

判断某个宏是否被定义,若是被定义则执行程序段1,,和if……else类似,就是表达式的用法有点不同,

#ifdef  宏名
    程序段1
#else
    程序段2
#endif

 假设我们没有定义宏,如下打印的会是#else的内容

int main()
{
#ifdef __DEBUG__
	printf("宏定义了");
#else 
	printf("未定义");
#endif
	return 0;
}

#ifndef:

#ifndef恰好和#ifdef相反,兄弟反目成仇了;宏未被定义,则会进入程序段1

#ifndef 宏名
    程序段1 
#else 
    程序段2 
#endif

 如下代码,打印的则是#ifnedef的内容

int main()
{
#ifndef __DEBUG__
	printf("未定义");
#else 
	printf("宏定义了");
#endif
	return 0;
}

四、defined函数:

defined函数的作用是判断某个宏是否被定义(功能是检查某个名称的常量是否存在。如果该名称的常量已定义,返回TRUE),若该宏被定义则返回1否则返回0,该函数经常与#if #elif #else配合使用

一般使用格式为:

defined 宏名 或 defined (宏名)----(个人建议,还是加上括号比较好)

上文提到有#ifdef、#ifndef来判断宏名是否被定义,乍一看defined有点多余,其实不然,#ifdef和#ifndef仅能一次判断一个宏名,而defined能做到一次判断多个宏名

int main()
{
#if defined(MAX)&&defined(MIN)
	printf("都被定义了");
#else
	printf("未被定义");
#endif
	return 0;
}

 2种写法都可以;

int main()
{
#ifdef MAX
	printf("定义了");
#else
	printf("未被定义");
#endif // MAX
#ifdef MIN
	printf("定义了");
#else
	printf("未被定义");
#endif // MIN
	return 0;
}

 

五、解决头文件重复引入的问题:

1、每个文件的开头用#ifndef:

可以针对一个文件中的部分代码,不受限与编译器,且具有标准,在工程量大的情况下,推荐使用(大家一起干活,容易出错)

 2、#pragma once 指令

指定该文件在编译源代码文件时仅由编译器包含(打开)一次。避免头文件(物理上的,并不是指的内容)的重复引入,VS的头文件就是用的该指令;有利于降低容错率,平时写代码用这个即可

五、总结:

        头文件的引用包括<>"" 2种方式,#definetypedef处理阶段(时间)、作用域不同,但作用域都只能在所在文件,不能跨文件使用。define(宏名)可以判断多个宏是否定义;

条件编译如下:

 

完                        结                      撒                 花

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值