预处理的常见情形

编译预处理是指在C++编译系统对C++源程序进行正式编译之前,由编译预处理程序对源程序中的预处理命令进行处理的过程。常用的预处理命令有:#define、#include、#ifdef、#ifndef、#else及#endif等,C++程序中引入预处理命令的主要目的是为了改进程序设计环境、提高编程效率。预处理命令不是C++本身组成成分,所以不能直接对其进行编译,而只能“抢”在源程序编译之前作一些“特殊处理”,将预处理命令“翻译”成C++程序能识别的语句。

预处理命令书写要求:

1.为了与C++语句相区分,命令必须“#”打头,#是命令动词的组成成分。

2.命令动词区分大小写。

3.预处理命令不是C++语句,书写结束后不能加分号。

4.一般地,预处理命令单独占一行,可以放在程序的开头、中间或末尾等任何位置。

宏的定义:#define 宏名[(形参列表)][字符串]

源程序开始编译前,将所以引用的宏名“替换”成对应的字符串,然后再编译源程序

举例:
#define array_size 100
#define NOT !
#define AND &&
#define OR ||
#define S(r) 3.14*(r)*(r)

注:1.宏名一般用大写字母表示

2.宏分为带参宏和无参宏。带参宏中,当形参为多个时,其间用逗号“,”隔开,每个形参即为一个标识符(一般为变量)。

3.字符串即为替换宏名的一串字符串(替换后不一定解析为字符类型),包括空格、反斜杠、引用

号等。若为带参宏,一般还应含有“形参”。书写时无需双引号定界。

4.如果在字符串中含有运算符,需要注意替换后的运算优先级,为了达到“预期运算顺序”,通常在字符串的相应位置加括号。如:

#define Pl 2+1.14
#define Pl2(2+1.14)
int r(3);
float s;
s=Pl*r*r;    //替换后s=2+1.14*3*3
s=Pl*r*r;    //替换后s=(2+1.14)*3*3

 5.若“字符串”省略,仅定义宏名。

 6.宏的定义可以嵌套,即一个宏定义的字符串中出现另一个宏名,引用是层层替换。如:

#define A 10
#define B A*10
cout<<B+10;    //输出110

7.宏定义中,是用字符串对宏名作“机械”的置换或参数替换,不作合法性检查。如:

#define Pl 3.l4
float s=Pl*3*3;    //出错
#define DIV(a,b) a/b
cout<<DIV(3.0,0);    //出错

8.宏一旦定义,便可以使用,而且宏引用的每处在预处理时都替换成相同的字符串,除非重新定义,永不改变,所以宏名又称作“符号常量”。

9.如果在程序中多处使用同一“字符串”,为了简化程序源代码一般将其定义成宏。

10.宏不是变量,宏定义不分配内存空间。

宏的使用

宏的使用,就是在程序中引用宏。

如果宏名出现在字符串常量中,将不视为宏引用,即不对其进行宏替换。

#define Pl 3.14
cout<<"Pl="<<Pl<<endl;    //输出Pl=3.14

如果宏名作为标识符部分成份出现,将不视为宏引用。如:

#define Pl 3.14
float Pl2=3.14159;
cout<<Pl2<<endl;    //输出3.14159 而不是3.142

若引用的宏为带参宏,则实参与形参的个数应相等。

宏引用根据宏的定义位置是有作用域的。作用域从定义点开始到本程序单元或命令行“#undef宏名”结束。

在程序中出现宏,称为“宏引用”或“宏调用”;在源程序编译前,将程序中的宏名替换成对应的字

符串,称为“宏展开”或“宏替换”

#include<iostream>
using namespace std;
#define max2(x,y) (x)>(y)?(x):(y)
#define max3(x,y,z) max2(max2(x,y),z)
int main()
{
	int a, b, c, max;
	cout << "a="; cin >> a;
	cout << "b="; cin >> b;
	cout << "c="; cin >> c;
	max = max3(a, b, c);
	cout << "MAX=" << max << endl;
	return 0;
}
#include<iostream>
using namespace std;
#define INPUT cin>>a>>b>>c
#define OUTPUT cout<<a<<b<<c<<endl
int main()
{
	int a, b, c;
	INPUT;
	OUTPUT;
	return 0;
}

宏与函数的区别

宏允许嵌套定义;而函数不能。


函数中的形参与实参要求有数据类型;而带参宏的形参没有数据类型,只是一个符号而已,实
参从理论上讲可以为语法范围内的任何一种数据类型。


函数调用是先求出实参的值,然后再传递给形参;而带参宏引用只是进行“简单”的实参替换形参。


函数调用是在程序运行时进行,并且为形参分配内存单元;而宏展开是在源程序编译前进行,不为其分配内存单元,不进行值的传递,也不存在返回值。


是宏展开会增加源程序代码;而函数调用保持源程序代码不变。

宏替换不会占用程序运行时间,仅延长编译时间;而函数调用要占用程序运行时间,用于分配内存单元、值传递过程消耗等。

文件包含

文件包含是指在一个C++文件中包含另一个C++文件的全部内容。一般地,用C++写程序往往不只是一个文件,而为了提高程序的编写效率,更为了引用其他文件中的功能模块,由此引入文件包含

#include<文件名>
#include"文件名"

源程序开始编译前,将指定“文件”中的内容替换对应包含命令,使文件中的全部内容成为C++程序文件中的一部分。

注:1遇被包含文件名用于指定C++程序引用的文件,是一个文本文件,又称“头文件”或“标题文件”
一般地,C++系统头文件不带扩展名,C式系统头文件扩展名为.h。C++中的系统头文件般包括函数原型、宏定义、结构体定义、全局变量定义、类定义和对象定义等.


2.如果被包含文件被修改,凡包含此文件的所有C++程序文件都要全部重新编译.


3.用尖括号引用被包含文件,系统到编译系统指定的文件夹中寻找被包含的文件(标准方式)。“尖括号”方式一般用于包含系统提供的头文件。

4.用双引号引用被包含文件,系统先到当前文件夹中寻找被包含的文件,若找不到,到编译系统指定的文件夹中寻找。“双引号”方式一般用于包含用户自定义的头文件。一般地,双引号之间可以指定包含头文件的路径,用于指定包含头文件的位置。

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

6.在一个被包含文件中可以包含另一个被包含文件,即文件包含可以嵌套。

7.#include命令通常位于C++程序文件开头。

条件编译

一般情况下,源程序中的所有代码行都参加编译。而条件编译是指源程序中某段代码通过条件来决定是否参加编译。在大型应用程序中,可能会出现某些功能不需要的情况,这时就可以利用条件编译来选取需要的功能进行编译,以便生成不同的应用程序,供不同用户使用。此外,条件编译还可以方便程序的逐段调试,简化程序调试工作。
格式1:

        #if 表达式

                程序段A

        [#else

                程序段B]

         #endif

判断表达式的值,若为真(非0)则编译程序段A;否则编译程序段B。

#include<iostream>
using namespace std;
#define N 5
#define FLAG true
int main()
{
	int a[N], m, * p = a, i = 1;
	while (p < a + N)
	{
		cout << "请输入第" << i++ << "个整数:";
		cin >> *(p++);
	}
	p = a;
#if FLAG
	m = *p;
	while (++p < a + N)
		if (m < *p)
			m = *p;
	cout << "MAX=" << m << endl;
#else
	m = *p;
	while (++p < a + N)
		if (m > *p)
			m = *p;
	cout << "MIN=" << m << endl;
#endif
	return 0;
}
#include<iostream>
using namespace std;
#define LETTER false
int main()
{
	char* str = "C++ Language Program", c;
	int i = 0;
	while ((c = *(str + i)) != '\0')
	{
		i++;
#if LETTER
		if (c >= 'a' && c <= 'z')
			c -= 32;
#else
		if (c >= 'A' && c <= 'Z')
			c += 32;
#endif
		cout << c;
	}
	cout << endl;
	return 0;
}

格式2:

        #ifdef 标识符

                程序A

        [#else

                程序B]

        #endif

若标识符是已定义过的宏名,则编译程序A,否则编译程序B

格式3:

        #ifndef 标识符

                程序A

        [#else

                程序B]

        #endif

若标识符不是已定义过的宏名,则编译A,否则编译程序B

格式3和格式2功能恰恰相反

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值