预处理指令最终篇和#和##的实例
目录
今天我们主要学习深度理解条件编译,和其他预处理指令相关内容
希望大家今天也要心情愉悦哦。
深入理解条件编译
1.条件编译的使用
1.1 #ifdef 和 #ifndef区别。
1.2 #if 和 #ifdef的区别
1.3 #if defined(宏)实现 #ifdef功能
1.4可以使用逻辑的形式同时判断两个宏的成立,来进一步判断条件编译的结果
1.5 条件编译可以嵌套吗?
1.6 剩下的多分支和单分支的实现在上一篇博客已经说过不在赘述。
2. 为什么要有条件编译?
深入理解文件包含
2.1 为什么这个东西可以避免头文件重复包含?
2.2文件重复包含的后果。
其他预处理指令讲解
3.1 #error 和 #pragma message ()的对比讲解
3.2 #pragme 相关的预处理指令
3.3 #line
关于 # 和 ## 的例子
#的作用:是把参数的符号转化为 "字符串"。
##的作用:把宏的参数组合形成新的符号。
下期预告:
下期主要讲解 指针相关 内容
下期更精彩哦~~~
今天我们主要学习深度理解条件编译,和其他预处理指令相关内容
希望大家今天也要心情愉悦哦。
深入理解条件编译
条件编译在上一篇博客已经讲过了,但是因为有些东西还是不够细致,所以今天做个补充。
1.条件编译的使用
上一篇博客说了写使用方法但是还有些方法没有说,下面一起看一些例子吧。
1.1 #ifdef 和 #ifndef区别。
这两个条件刚好是相反的,前者是的判断宏是否被定义,后者是对前者结果进行逻辑取反
#define MAXint main(){#ifndef MAXprintf("MAX被定义\n");#endif#ifdef MAXprintf("MAX被定义\n");#endifreturn 0; }
这通过产生了 .i 文件的形式,进行直观表达。
1.2 #if 和 #ifdef的区别
#if 是判断后面宏的逻辑上的真假 #ifdef只是判断宏的定义与否
#define MAX 0int main(){#if MAXprintf("MAX是真\n");#elseprintf("MAX是假\n");#endif#ifdef MAXprintf("MAX已被定义\n");#endifreturn 0;}
这里可以看出,虽然MAX的值是0,但是MAX是被定义的(即使宏为空,依然也是被定义的)
1.3 #if defined(宏)实现 #ifdef功能
看下代码,理解下#if后必须是常量表达式,和模拟实现#ifdef。
#define MAXint main(){#if defined(MAX)printf("MAX已定义\n");#endif#ifdef MAXprintf("2.MAX已定义\n");#endif#if MAX //因为MAX没有值,所以报错printf("MAX为假\n");#endifreturn 0;}
可以看出来#if defined模拟实现#ifdef的效果,下面的那个#if只是起对比作用
同理,实现#ifndef的话使用 #if !defined就可以了(本质就是对值进行逻辑取反)
1.4可以使用逻辑的形式同时判断两个宏的成立,来进一步判断条件编译的结果
如果同时有两个宏有需要判定呢?该怎么办呢?
看例子:
#define MAX 1#define MIN 0int main(){#if (defined(MIN) && defined(MAX))printf("MAX,MIN同时被定义");#elseprintf("未全部定义\n");#endifreturn 0;}
这样就可以同时判断两个宏是否被定义的情况了。(同理,逻辑或成立,逻辑与也是可以的,逻辑取反也是可以的,自己动手试试呀)
1.5 条件编译可以嵌套吗?
就像是if语句一样是可以嵌套的。不废话,看例子:
#define MAX #define MINint main(){#if defined(MAX)#if defined(MIN)printf("MIN定义\n");#endifprintf("MAX定义\n");#elseprintf("未定义\n");#endifreturn 0;}
这样来看,好像一个if语句的嵌套,每个#if defined(宏)是判断表达式要不要执行。(同理,你可以看下不同的宏,是否定义带来的不同的条件编译,产生的不同的结果)
1.6 剩下的多分支和单分支的实现在上一篇博客已经说过不在赘述。
单分支多分支条件编译
2. 为什么要有条件编译?
通过裁剪代码,快速实现某种目的(比如一些功能的裁剪,和一份代码的免费版和收费版维护,和一些代码的跨平台性)
深入理解文件包含
2.1 为什么这个东西可以避免头文件重复包含?
1 #ifndef __TEST_H__ 2 #define __TEST_H__ 3 //头文件的内容 4 #endif //__TEST_H__
首先这是条件编译的知识,
第一行是判断 __TEST_H__ 这个宏有没有被定义,
第二行是定义__TEST_H__ (把这个宏定义)
第三行是头文件内容
第四行是#endif条件编译结束。
综上所述,这个东西每一个头文件都需要这样写。
所以我们推荐使用 #pragma once 来防止头文件被引用。
2.2文件重复包含的后果。
我们要知道文件重复包含,最大的后果就是很多声明文件重复了,很多的东西重复了,就导致代码的编译效率低下。
你看,如果头文件被重复包含,那么就会导致多次声明,虽然没有出错,但是在编译效率上降低了。
其他预处理指令讲解
3.1 #error 和 #pragma message ()的对比讲解
#error就是让编译器打印一些字符,是以 "错误" 的方式
例 :
这样打印的消息是不可以通过编译的,所以叫 "错误" 的方式。
而#pragma message ()则是警告或者叫"提示"的方式。
他们都可以用在条件编译中,#error是错误级别的,#pragma message ()是提示级别的。
3.2 #pragme 相关的预处理指令
#pragme once防止头文件重复包含。
#pragme pack()改变默认对齐数。
#pragme warning(4996)是VS下,接口型警告,常见的是scanf的警告。
3.3 #line
修改当前的文件名和行数。
看例子:
关于 # 和 ## 的例子
#的作用:是把参数的符号转化为 "字符串"。
看个例子,把数字转化为字符输出。
#define NUM(s) #sint main(){printf("π:"NUM(3.1415926)"\n");return 0;}
这样就可以把参数转化为字符,输出了。
##的作用:把宏的参数组合形成新的符号。
看个例子 ,用宏求一个数的科学计数法的值
这样不太直观,我们看下预处理后的结果吧。
这样看是不是就是浮点数的科学计数法了。