预处理命令总结

来源:互联网 发布:mysql 查询锁表 编辑:程序博客网 时间:2024/06/04 18:05

     

     有的时候需要在编译之前完成一些任务或功能,如在C语言中定义数组时需要指定数组的大小(能容纳元素的个数),这个时候就只能用常量作为数组大小。可能这个大小在多处都有用到,为了减少修改的麻烦和提高程序的可读性,一般用宏定义来替代这个常量(在C++中对const的定义进行了扩充,可以通过const来定义常量来替代宏定义,因为那样更安全)。


宏定义

不带参数的宏定义

#define 标示符  字符串

a)      宏定义是用宏名代替一个字符串,也就是作简单的置换,不作正确性检查。

b)     宏定义不是C语句,不必在行末加分号。如果加了分号则会连分号一起进行置换。

c)      #define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。通常,#define命令写在文件开头,作为文件一部分,在此文件范围内有效。

d)     可以用#undef命令终止宏定义的作用域。

e)     在进行宏定义时,可以引用已定义的宏名,可以层层置换。

f)       对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行置换。

g)      宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。

h)     在宏定义时,在字符串末尾加一个“\”后换行(不要在“\”后面加空格),将把第二行的字符串拼接到前一行作为宏定义字符串的一部分。

例如:#defineWORD (“abcd\          //注意“\”后面没有空格

efg\n”)

printfWORD;//输出abcdefg

注意:在printf和WORD间的空格不能少,否则将它们作为一个整体,而整体printfWORD没有定义。

i)        在头文件中使用#ifndef/#define/#endif来避免重复编译,还可以在头文件开头使用#pragmaonce,它保证该文件只被编译一次。


带参数的宏定义

#define 宏名(参数表) 字符串

a)      对带参数的宏定义是这样展开置换的:在程序中如果有带实参的宏,则按#define命令行中指定的字符串从左到右进行置换。如果串中包含宏中的形参,则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符,则保留。这样就形成了置换的字符串。

例如:#defineS(a,b) a*b

              int s = S(1+2,2+3);//结果s= 8,第一个实参1+2传给a,第二个实参2+3传给b,只作简单替换,不进行计算。然后再用字符串进行替换,即S(1+2,2+3)被替换为1+2*2+3=8

注意:如果想让(1+2)和(2+3)进行计算,可以这样 #define S(a,b) (a)*(b)

b)     在宏定义时,在宏名和带参数的括号之间不应加空格;否则将空格以后的字符都作为替代字符串的一部分。


带参数的宏定义与函数的区别

a)      函数调用时,先求出实参表达式的值,然后代入形参。而使用带参数的宏只是进行简单的字符替换。

b)     函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏展开则是在编译前(即预处理)进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有返回值的概念。

c)      对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时代入指定的字符串即可。宏定义时,字符串可以是任何类型的数据。

d)     调用函数只可得到一个返回值,而用宏可以设法得到几个结果。例如:#defineS(R,L,S) L=2*PI*R;S=PI*R*R//得到周长和面积

e)     使用宏次数多时,宏展开后源程序变长,因为每展开一次都使程序增长,而函数调用不会使源程序变长。

f)       宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)

g)      如果善于利用宏定义,可以实现程序的简化,可以事先将程序中的“输出格式”定义好,以减少在输出语句中每次都要写出具体的输出格式的麻烦。


“文件包含”处理

1.一个#include命令只能指定一个被包含文件,如果要包含n个文件,要用n个#include命令。

2.在#include命令中,文件名可以用双撇号或尖括号括起来。二者的区别是用尖括号时,系统到存放C库函数头文件的目录中寻找要包含的文件,这称为标准方式。用双撇号时,系统先在用户当前目录(即包含文件所在的目录)中寻找要包含的文件,若找不到,再按标准方式查找。若文件不在当前目录中,在双撇号内应给出文件路径。

3.被包含文件与其所在的文件,在预编译后已成为同一文件。因此,如果在被包含文件中有全局静态变量,在包含文件中有效,不必用extern声明。

4.程序编译过程一般为:
C源程序头文件-->预编译处理(cpp)-->编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件
文件包含,一般是头文件,所引用的头文件里定义了你需要的函数、类型或者变量的定义,形式为#include<头文件>;
文件的连接,应该是程序在生成可执行文件时所需要的一些引用,一般分为静态和动态链接两种。

C源程序头文件-->预编译处理(cpp)-->编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件

文件包含,一般是头文件,所引用的头文件里定义了你需要的函数、类型或者变量的定义,形式为#include<头文件>;

文件的连接,应该是程序在生成可执行文件时所需要的一些引用,一般分为静态和动态链接两种。


条件编译

1.  #ifdef标示符

程序段1

#else

程序段2

#endif

如果之前标示符被定义过则执行程序段1,否则执行程序段2。

当然,也可以没有#else部分。即

#ifdef 标示符

        程序段1

#endif


2.  #ifndef标示符

程序段1

#else

程序段2

#endif

这个则刚好与第一个情况相反


3.  #if表达式

程序段1

#else

程序段2

#endif

如果表达式的值为真,则执行程序段1。否则,执行程序段2.

 

1 0
原创粉丝点击