命令行定义
C语言的大部分编译器都提供了一种功能,允许在命令行当中定义符号,用于编译过程的程序,通常是在Linux环境下使用,在windows环境下一般是不可以的,那这个是什么意思呢?举个例子:
intmain() { intarr[SIZE]; inti=0; for(i=0;i<SIZE;i++) { arr[i]=i; } for(i=0;i<SIZE;i++) { printf("%d" ,arr[i]); } printf("\n"); return0; }
可以看到上面的程序当中有一个没有初始化和定义的变量SIZE,那程序正常情况下是跑不起来的,是会报错的,那应该怎么在没有修改程序的情况下,让它跑起来,在Linux环境下面,可以在命令行规定,规定格式是这样的:
gcc-DSIZE=10test.c
这样编译器就会知道SIZE是10,程序就可以正常运行起来。
条件编译
> 在编译一个程序的时候,当我们有部分语句不需要的时候,可以进行注释,那有没有其他方法呢?有,可以用条件编译指令,那条件编译指令具体怎么使用,往下看:
intmain() { inti=0; intarr[10] = { 0 }; for(i=0; i<10;i++) { arr[i] =i; printf("%d", arr[i]);//为了知道上面的数是否放到数组里面 } return0; }
可以看到上面代码中,for循环内的printf是用于验证我们的数字成功放到了数组当中没有,那现在我们知道放成功了,不需要它了,但是又不想删除和注释,这个时候使用条件编译指令当中的一个:
intmain() { inti=0; intarr[10] = { 0 }; for(i=0; i<10;i++) { arr[i] =i; //如果_ DEBUF _为真,进入到里面执行语句printf("%d", arr[i]);//为了知道上面的数是否放到数组里面//结束标志 } return0; }
那这样写,对于_ DEBUF _,它的值是为假的,那就不会走ifdef,那就不会运行printf,这样就实现了我们不想删除也不想注释,但是让程序不跑某些代码的功能了,常见条件编译指令还有很有:
//1//常量表达式//...//这里的常量表达式由预处理求值//比如上面程序当中的_ DEBUG _,编译器会知道是什么,但是必须要提前声明//2.多个分支的条件编译//常量表达式//...//常量表达式//...//...//3.判断是否被定义//4.嵌套指令unix_version_option1(); unix_version_option2(); msdos_version_option2();
文件包含
我们知道#include是用于包含头文件的,在进入这个头文件的时候,就对头文件指向的文件进行了编译,这个时候在编译器眼里#include的地方就是包含的头文件的内容,所以,我们包含了多少次头文件,就会替换多少次,所以我们包含了多少次头文件,就编译了多少次头文件,所以最好不要重复包含同一个头文件很多次
头文件包含查找规则
在包含头文件的时候,我们发现,有两种包含方式,一种是<>,另一种是"",那它们两个包含方式有什么区别呢?
对于""而言,它会先在源文件所在目录下查找,如果没有找到这个头文件,编译器就像查找库函数头文件一样在标准位置查找头文件,如果没有在标准位置查找到,就提示编译错误,而标准位置就在编译器的下载目录当中,比如我用的vs2020,那标准位置就在我的vs2020的默认下载路径。
而<>,会直接在标准位置查找,找不到就报错,对于库函数的头文件,也可以用""来引,但是就会降低效率,因为本来就存放在标准位置,直接就可以查,但是用“”先查本地,相比较就会慢一点,而且也不容易区分本地的头文件和库函数的头文件,所以对于头文件用什么引,要根据情况而定。
嵌套文件包含
如上图所示,comn.h和comn.c是公共模板,test1.h和test1.c使用了公共模块,test2.h和test2.c也使用了公共模块,test.h和test.c使用了test1模块和test2的模块。
那这样test是不是同时包含了两份comn.h的内容,那就重复包含了,那有没有什么方法解决这个问题呢?使用条件编译,在每个头文件最前面加上条件编译指令,如下所示:
//头文件包含的内容
或者:
这样可以避免掉我们的头文件重复包含
其他预处理指令
还有一些预处理指令:
//...