程序环境和预处理3

目录

3.4 命令行定义:

3.5 条件编译 :

3.6 文件包含:

3.6.1 头文件被包含的方式:

3.6.2 嵌套文件包含: 

四、其他预处理指令:


3.4 命令行定义:

VS编译器下不方便进行演示,所以在此使用Linux操作系统下的 gcc编译器进行演示:

所谓命令行定义即指,命令行中定义符号、

当我们根据 同一个源文件,即源文件中代码不变, 要编译出一个程序的 不同版本 的时候,这个特性有点用处,(假定某个程序中声明了一个某个
长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大写,我们需要一个数组能够大写。

扫描二维码关注公众号,回复: 14288703 查看本文章

如果直接去编译,则结果为:

 

或者编译指令可写成:

gcc -D M=10 test.c

此时,M=10M=100,并不是在代码中定义的,而是在编译的时候指定的、

 

此时M就是在命令行中定义的,所以叫做命令行定义,在命令行中使用相关的参数定义符号就叫做命令行定义,所以这种方法就可以不需要改

代码,通过命令行定义的方式来实现相应的功能、

windows操作系统下的VS编译器中,虽然也有命令行参数,但是也是不可以的,不能成功编译,所以只能在Linux操作系统下的gcc编译器中

可以使用上述方法去完成任务、

3.5 条件编译

所谓条件编译即指设定一些条件满足条件就进行编译,不满足条件就不进行编译在编译一个程序的时候我们如果要将一条语句(一组语

句)编译或者放弃编译是很方便的。因为我们有条件编译指令

比如说:
调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译、

条件编译指令就是预处理指令,如上图,假设符号PRINTF未进行定义,则 #ifdef PRINT 和 #endif 中间的内容就会在处理阶段被删除了,就相当

于是被注释掉了,因为注释在预处理阶段就会被删除,而这里如果不进行编译的话,在预处理阶段也会被删除,所以和删除注释是一样的,如果

该符号进行了编译,那么在预处理阶段就不会把这些内容删除,而是会被保留下来、

常见的条件编译指令:

一、单分支的条件编译:

#if 常量表达式
//...
#endif

//常量表达式由预处理器求值、
如:
#define  __DEBUG__  1
#if __DEBUG__
 //..
#endif

 

 二、多个分支的条件编译:

#if 常量表达式
 //...
#elif 常量表达式
 //...
#else
 //...
#endif

三、判断是否被定义: 

#if defined(symbol)
#if defined symbol
#ifdef symbol

#if !defined(symbol)
#if !defined symbol
#ifndef symbol

写法二中,符号TEST和符号HEHE可以不放在括号里,也是可以编译的,除此之外还可以对该 #if defined 后面的符号做&&或者是|| 处理、 

符号EOFstdio.h该头文件中、

四、嵌套指令:

#if defined(OS_UNIX)
 #ifdef OPTION1
 unix_version_option1();
 #endif
 #ifdef OPTION2
 unix_version_option2();
 #endif
#elif defined(OS_MSDOS)
 #ifdef OPTION2
 msdos_version_option2();
 #endif
#endif

常量表达式:

所谓常量表达式即指:值不会改变并其在编译期间进行求值的表达式:

字面值:是一个不能改变的值,如数字、字符、字符串等,单引号内的字符字面值,双引号内的是字符串字面值、

字面值类型(literal type):算数类型、引用和指针等、

1、字面值常量是常量表达式,如123,'a',3.14等等、

2、跟字面值常量相关的一些表达式,如123+3.14,2<<2等等、

3、常量表达式初始化的const对象也是常量表达式,比如:int const a=5,或者是 const int a=5,由于5是常量表达式,拿着常量表达式初

始化的const修饰的对象,那么此const修饰的对象也是常量表达式,const修饰变量的时候,写成上面两种都是可以的,

const int a =1;		//1是常量表达式,使用常量表达式初始化const修饰的对象时,该对象也是常量表达式,                
                    //所以a也是常量表达式、

cosnt int b=a+1;	//1和a都是常量表达式,所以a+1也是常量表达式,使用常量表达式初始化const修饰的 
                    //对象时,该对象也是常量表达式,所以b也是常量表达式、

int c=2;		    //初始值是字面值常量,但是对象c未被const修饰,所以c是变量而不是常量表达式,c 
                    //的类型是普通的int整型、

const int d=fun();	//fun()值要在运行时得到,虽然对象d被const修饰,但是初始值并不是常量表达式,所 
                    //以,d也不是常量表达式。

3.6 文件包含:

当我们使用库函数或者是自定义函数的时候,往往要进行头文件的包含,则就需要使用预处理指令#include,它可以包含头文件、

预处理指令#include 可以使 另外一个文件被编译, 就像它实际出现于 #include 指令的地方一样、
这种替换的方式很 简单
预处理器 删除这条指令 ,并用包含文件的 内容替换、

3.6.1 头文件被包含的方式:

本地文件包含 :
#include "filename"
查找策略:
先在 自定义的源文件所在目录(路径)下查找 ,如果该头文件 未找到 ,编译器就像查找库函数头文件一样在 标准位置 库函数头文件的目录下,
库函数头文件所在的路径下 )查找该头文件,如果再 找不到就提示编译错误、
Linux环境的标准头文件的路径:
/usr/include
VS2013环境的标准头文件的路径:
E:\天津工业大学\VS2013\VC\include

由于符号EOF是包含在stdio.h头文件中的,可以通过该符号来找库函数提供的头文件stdio.h所在的位置,就可以找到标准位置了,右击符号

EOF,转到定义,在该页面中右击右上角的stdio.h,点击打开所在的文件夹就可以找到了、

 库文件包含 :

#include <stdio.h>

查找策略:

直接标准位置(库函数头文件的目录下,库函数头文件所在的路径下)查找该头文件如果找不到就提示编译错误、

3.6.2 嵌套文件包含: 

如果出现这样的场景:同一个头文件被重复多次包含、
comm.h comm.c 公共模块、
test1.h test1.c 使用了 公共模块
test2.h test2.c 使用了 公共模块
test.h test.c 使用了 test1模块和test2模块、
这样 最终程序 中就会出现 两份comm.h 的内容,这样就造成了 文件内容的重复、
已知,在 预处理阶段完成了 头文件的包含,即,先把 该条指令删除,再把 头文件的中所包含的内容拷贝了一份进去,但是,如果 同一份头文件
多次重复包含的话,那么就会 拷贝多份该头文件中的内容放进去,就会 造成冗余,那么如何才能做到 避免这种情况发生呢?
这样就可以 避免头文件的重复引入

四、其他预处理指令:

常见的预处理指令有:#define、#if、#undef、#elif、#include、#ifdef、#endif、#ifndef、#else、#error、#pragma、#line等等,具体见C语言深

度剖析,其中,#pragma pack(4),设置默认对齐数为4#pragma pack( ) === #pragma pack(8),,取消设置默认对齐数和设置默认对齐数是8

作用是一样的,因为,VS编译器下本来默认的对齐数就是8,除此之外还有:#pragma comment()等就不再一 一列举了、

关于程序环境和预处理的知识到此结束,感谢大家收藏加关注哦~

猜你喜欢

转载自blog.csdn.net/lcc11223/article/details/122856159