小白的编程经验(预处理指令)

程序员所编写的代码并不能被真正的编译器编译,需要一段程序把代码翻译一下。翻译的过程叫做预处理,负责翻译的程序叫做预处理器,被翻译的代码叫做预处理指令,以#开头的代码都是预处理指令。

可以使用以下命令查看预处理过程:

    gcc -E code.c     把预处理的结果显示到终端上
    gcc -E code.c -o code.i     把预处理结果存储到code.i预处理文件中

常用的预处理指令有文件包含(#include)、宏定义(#define)、条件编译(#ifdef)等。

文件包含(#include)

#include <> 从系统指定路径查找并导入头文件
#include “” 从当前路径下查找,如果找不到再从系统指定路径查找并导入文件

此外,可以通过编译参数指定查找路径 -I /path,也可以通过修改操作系统的环境变量来指定头文件的查找路径

定义宏(#define)

C语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为宏的标识符称为“宏名”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为宏替换或宏展开。

宏定义是由源程序中的宏定义命令完成的。宏替换是由预处理程序自动完成的。

1)宏常量

定义: #define 宏名 数据

举个例子:

  				#include<stdio.h>

                #define MAX 50
                int main(int argc,const char* argv[])
                {
                    for(int i = 0;i<MAX;i++)
                    {   
                        printf("%d ",i);
                    }   
                }

在程序预处理时,会将所有的MAX替换成为 50等价于下面的循环

				for(int i = 0;i<50;i++)
                {   
                     printf("%d ",i);
                }   
优点:

提高代码可读性、提高可扩展性(方便批量修改)、提高安全性
注意:一般宏名全部大写,末尾不加分号(因为分号也会被替换进入代码),由于宏相当于常量,因此不能在程序中赋值,会报错。

预定义的宏(常用)
宏名作用类型(占位符)
func获取函数名%s
FILE获取文件名%s
DATE获取日期%s
TIME获取时间%s
LINE获取行号%d

2)宏函数

定义:#define 宏函数名(变量1、变量2…) 自定义操作

举个例子:

		    #include<stdio.h>
		
		    #define SUM(a,b) a+b
		    int main(int argc,const char* argv[])
		    {
		        printf("%d ",SUM(1,2)); 
		    }

宏函数不是真正的函数,只是替换,不检查参数类型,只是值替换。宏函数没有返回值,只有表达式的计算结果。

注意:定义宏常量、宏函数、不能直接换行,可以使用续行符\放在末尾换行,也可以使用大括号保护代码

3)宏的二义性

由于宏所处的位置,参数不同导致宏有不同的解释和功能,和我们预想的结果不同。这种叫做宏的二义性。
举个例子

		    #include<stdio.h>
		
		    #define SUM(a,b) a+b
		    int main(int argc,const char* argv[])
		    {
		        printf("%d ",SUM(1,2)*2); 
		    }

运行结果是 5 而不是预想的 6 。为什么会这样呢?很简单,把宏代入替换就知道了。

		    #include<stdio.h>
		
		    #define SUM(a,b) a+b
		    int main(int argc,const char* argv[])
		    {
		        printf("%d ",1+2*2); 
		    }

SUM(1+2)替换成为1+2,但是右边的2先与乘2运算,所以出现二义性,我们以为是6,但是事实上是5。

如何避免二义性
1、宏函数整体代码加小括号

解决整体与外部先运算问题

		    #include<stdio.h>
		
		    #define SUM(a,b) a+b
		    int main(int argc,const char* argv[])
		    {
		        printf("%d ",SUM(1,2)*2); 
		    }

运行结果是5,预期结果是6

2、宏函数每个参数都加小括号

解决内部参数间先运算问题

		    #include<stdio.h>
		
		    #define SUM(a,b) a*b
		    int main(int argc,const char* argv[])
		    {
		        printf("%d ",SUM(1+2,2)); 
		    }

运行结果是6,预期结果是5

3、使用宏函数时不要使用自变运算符
避免变量频繁自变

		    #include<stdio.h>
		
		    #define SUM(a) a*a
		    int main(int argc,const char* argv[])
		    {
		    	int a = 2;
		        printf("%d ",SUM(++a)); 
		    }

运行结果是16,预期结果是9

条件编译(#ifdef)

根据条件决定让代码是否参与最终的编译。

1) 头文件卫士:写在头文件中,防止头文件重复包含

		#ifndef 宏名(头文件名全大写,_代替.
		#define 宏名
		头文件内容
		#endif //宏名

#ifndef 宏名 ,如果这个宏名未定义执行下面的语句
#define 宏名,定义这个宏(如果没定义则定义这个宏,一旦定义下一次就不会进入上面的判断)
#endif //宏名,结束最外面的ifndef,加上注释//宏名,让别人知道是和最外面的头文件卫士对应。

2)版本控制

#if 条件1
         内容1…
#elif 条件2
         内容2…
#else
         内容3…
#endif
举个例子:

 				#include<stdio.h>

                #define VERSION 4
                int main(int argc,const char* argv[])
                {
                    #if VERSION > 3
                        printf("最新版本");
                    #elif VERSION > 2
                        printf("勉强能用");
                    #else
                        printf("快升级");
                    #endif
                }

可以简单的当作if语句使用,但是与if不同的是,不满足条件的语句甚至不会出现在编译结果中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值