版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
函数和编译预处理第5章引言函数的定义和调用函数的原型说明与值调用函数的嵌套和递归调用作用域和存储类内联函数具有缺省参数值的函数函数重载编译预处理程序的多文件组织本章学习要求掌握函数定义的格式;掌握函数原形的概念及其与头文件的关系;掌握两种形式的函数调用(表达式中的函数调用和语句中的函数调用);掌握函数调用过程中参数传递的原理;掌握函数重载的方法;掌握保留字inline的含义与使用;了解函数和变量的作用域与生存期;掌握和应用宏定义、条件编译、文件包含。引言随着模拟对象的复杂性增加,程序将会变得越来越复杂和冗长。在编写一个较大的程序时,为了便于管理,可以采用一些较好的编程策略,常用的方法是按功能或操作将程序分割成一些具有特定功能的、相对独立的且便于管理和阅读的小模块。本章主要介绍这种分割工具之一:函数,包括函数的定义、函数的调用、参数的传递方法、内联函数、函数的重载、变量的作用域等,另外简要介绍编译预处理以及程序多文件组织的编译和连接方法。
函数的定义和调用函数概述
函数定义
函数调用
5.1函数概述C++中的函数就是具有特定功能的模块。函数是构成C++程序的基本单位,C++程序的运行都是由主函数(main())开始,然后通过一系列函数调用来实现各种功能。从用户角度看,函数包括用户自定义函数和系统库函数。从函数的形式来看,函数可以分为无参函数、有参函数、无返回值函数和有返回值函数等。除了main()函数以外,一个函数既可以被其它函数调用,也可以调用其它函数。图5-l反映了函数的层次组织结构以及相互之间的调用关系。5.1.1系统库函数库函数也称为标准函数,是在C++编译系统中已经预先定义的函数。C++把一些常用的操作以库函数的方式提供给用户,包括常用的数学计算函数(如:sqrt()、fabs()等)、图形处理函数、标准输入/输出函数等。按功能对库函数进行分类,将同类库函数集中在一个头文件中,用户只要在程序中包含相应的头文件,就可以使用该头文件中的所有库函数。
用户自定义函数在程序设计过程中,用户可根据自己的需要将一段完成功能相对独立的代码定义为一个函数,这类函数称为用户自定义函数。本章将主要介绍用户自定义函数的定义和调用方法。
图5-1函数调用和被调用的层次关系main()Func1()Func5()Func3()Func2()Func4()函数定义对于库函数,在头文件中已经定义好了,调用函数前只需包含相应的头文件即可;对于用户自定义的函数,要先完成函数的定义,然后才可以调用它。根据函数定义和使用时参数的不同,可将函数分为两类:无参函数和有参函数。
无参函数
有参函数
函数返回值和return语句
5.1.2无参函数定义无参函数的一般格式为:
《<类型>》<函数名>(《void》) {…}//函数体
<类型>为函数返回值的类型,它可以是任一标准数据类型或导出数据类型,当没有返回值时,《类型》必须为void。函数名为用户给函数起的名字,其命名规则与标识符相同。<函数名>后的括号”()”称为函数调用运算符,对于无参函数,函数调用运算符内可以为空,也可以为void。函数返回值为整型时,可省略类型标识符int。当函数无返回值时,必须规定其类型为void。示例示例voidMessage(void){
cout<<”*************\n”;
cout<<”verygood!\n”;
cout<<”*************\n”;}该函数完成输出一些问候语。像这类与外部环境之间没有任何数据交换的函数,通常将其定义为无参函数。
有参函数定义有参函数的一般格式为:
《类型》<函数名>(<形参表>) {…}//函数体
有参函数中《类型》与<函数名>的含义和要求与无参函数一致。<形参表>为该函数的参数的类型和名字,<形参表>中的参数称为形式参数或形参,形参的个数是没有限制的,当超过一个参数时,参数间一定要用逗号”,”分隔开,且每个参数都要有类型说明。示例
在定义有参函数时,必须标明每个参数的类型,即使参数的数据类型相同,也不能将参数合在一起用一个类型说明符。
示例例如,求两个整数中的大数,函数可定义为:
intMax(intx,inty) //A {return(x>y?x:y);}该函数有两个整型参数x,y,函数的返回值是整型。
如上例A行写成以下形式就是错误的:
Max(intx,y)函数返回值和return语句函数的返回值也称为函数值。当函数有返回值时,在函数体中必须使用return语句来返回该函数的值。return语句的一般格式为:
return<表达式>;或
return(<表达式>);这里<表达式>可以为任意合法的表达式。当执行该语句时,首先求出表达式的值,再将该值转换成函数定义时规定的返回值的类型后,将其作为函数的返回值。
【例5.1】
求三角形的面积
函数调用C++中,函数的功能是通过在程序中对其调用来实现的。调用一个函数,就是把控制权转去执行该函数的函数体,函数体执行完之后,再将控制权转到调用函数处。
无参函数的调用格式
有参函数的调用格式
函数调用的使用方式
关于形参和实参的几点说明
【例5.2】
输入三个实数,求出其中的最大数图5-25.1.3无参函数的调用格式无参函数的调用格式一般为:
<函数名>()在调用无参函数前,必须先定义与它同名的无参函数。如:Message函数定义过之后,可以使用Message();来调用。
有参函数的调用格式有参函数的调用格式一般为:
<函数名>(<实参表>)<实参表>中的参数称为实际参数或实参,每个实参可以是任一合法的表达式。实参与形参不同,在实参前没有数据类型说明符。在调用有参函数前,也必须先定义,另外,调用有参函数时实参表和形参表的参数类型、个数必须匹配。
如:Max(4,9);及Max(a*4,b);函数的调用过程是:先计算各实参表达式的值(对有参函数),然后将所求的值传递给相应的形参,执行函数体,执行完毕再返回到函数的调用处,继续执行其后继语句。
函数调用的使用方式对于有返回值的函数,可以用两种方式调用:一种方式是函数调用出现在表达式中,其值(也称为函数值)参与表达式的运算;另一种方式是用一个语句来实现调用,即在调用格式后加上一个分号,构成函数调用语句,在这种情况下,函数返回值不起任何的作用。
对于没有返回值的函数,函数调用只能通过函数调用语句实现。
关于形参和实参的几点说明定义函数时指定的形参,在未出现函数调用时,它们不占用内存中的存储单元。只有在函数调用时,形参才被分配内存单元,在调用结束后,形参所占的内存单元也被释放。
调用时是将实参的值传递给形参,只是一个单向的传递关系。这是我们所说的“值传递”,形参值的改变不会影响实参的值。
实参与形参的类型应相同。当类型不一致时,则它们应该兼容,即按照不同类型数值的赋值规则,将实参转换为形参的数据类型后再传递给形参。
图5-2
函数的调用过程main()函数调用函数Max(a,b)函数Max(int,int)执行函数Max(int,int)的函数体将Max(a,b)的返回值赋给t调用函数Max(c,t)…结束向Max函数传递实参a,b向Max函数传递实参c,t函数的原型说明与值调用函数的原型说明
函数的值调用
5.2函数的原型说明C++中,与变量一样,函数的定义和使用也必须遵循先定义后使用的原则。如果函数的调用在函数的定义之前,就会出现编译错误。
如果函数调用在前、定义在后,则在函数调用之前,必须要对被调用的函数作原型说明。函数原型说明是一条语句,它必须以分号结束。函数原型说明的一般格式函数原型说明的目的是告诉编译程序,该函数的参数个数、各参数的类型和返回值类型。函数原型说明可以出现在程序中的任何位置,只要在调用前即可,且对函数原型说明的次数没有限制。
5.2.1函数原型说明的一般格式《类型》<函数名>(<形参表>);
或
《类型》<函数名>(<形参类型说明表>);
函数原型说明的形参和返回值的类型必须与对应的函数定义一致,对于第一种格式,原型说明中形参表的形参名可以和定义时的形参名不一致,又由于形参在原型说明中并不起任何作用,因此可以省略形参名(即第二种格式)。
函数的值调用C++中,形参与实参的结合方式有三种:传值调用、传地址调用和引用调用。
传值调用简称为值调用。值调用的特点是:在被调用函数的执行过程中,只能改变形参,不能改变实参。【例5.3】值传递应用——两数交换
图5-3值传递的好处是使得函数具有完全的独立性,函数的执行对其外界的变量没有影响。在值传递的情况下,函数只能通过return语句返回一个值或不返回任何值。要用函数实现两个数参数的交换,值传递是无法实现的,可以用地址传递或引用传递的方法。
5.2.2图5-3两数交换函数调用过程示意图35353553axbyybxa(a)交换前(b)交换后执行函数Swap(int,int)函数的嵌套和递归调用函数的嵌套调用
函数的递归调用
5.3函数的嵌套调用C++语言的函数之间是相互平行、独立的,在定义一个函数时,不允许在其函数体内再定义另一个函数,即函数不允许嵌套定义。但是函数之间的嵌套调用是可以的,即在定义一个函数时,在函数体内又调用另一个函数。图5-4【例5.4】求一元二次方程ax2+bx+c=0的根
5.3.1图5-4嵌套调用⑤⑥④③⑦②⑧main函数b函数a函数调用a函数结束调用b函数⑨①函数的递归调用在函数A的定义中调用函数A,或在函数A的定义中调用函数B,而在函数B的定义中又调用了函数A,这类函数的自调用关系称为递归调用。前一种情况称为直接递归,而后一种情况称为间接递归。在C++语言中,这两种递归调用都是允许的。
【例5.5】用函数递归调用方法求5!
【例5.6】将参数逐位正序和反序输出
【例5.7】Hanoi(汉诺塔)问题
5.3.2【例5.5】用函数递归调用方法求4!分析:由递推公式n!=n*(n-1)!,所以求n!的问题可以转化为求(n-1)!的问题,(n-1)!=(n-1)*(n-2)!,因此求(n-1)!的问题可以转化为求(n-2)!的问题,依此类推,直到转化为求1!的问题,根据定义,1!=1,则从1!=1开始将上述过程逆向求解,就可以求出n!。这种求解问题的方法可用函数递归调用方法实现算法演示程序代码算法演示程序代码#include<iostream.h>int
f(intn){ if(n==0||n==1)return1; //A elsereturnn*f(n-1); //B }voidmain(void){cout<<<<f(4)<<'\n';}【例5.6】将参数逐位正序和反序输出设计两个函数,其参数都为整型,分别将参数逐位正序和反序输出。要求用递归函数实现。
分析:要实现逐位正序或反序输出一个整数,则须获取它的各位数字。如1234,则用1234%10获得它的个位数,求十位数,则须先将个位数去掉,即1234/10,结果为123,再求个位数即可,依此类推。求一个整数K的各位数字时其递推关系为:
f1=Ktn=fn%10fn+1=fn/10
其中tn为整数K的第n位数字(从右数起),fn为去掉K的右边n-1位数后剩下的数。而该递推关系的结束条件为fn=0。程序代码
【例5.7】Hanoi(汉诺塔)问题这是一个经典的数学问题:有三个塔A、B、C,开始时A塔上有n个盘子,盘子大小不等,大的在下,小的在上,如图5-6所示。要求将这n个盘子从A塔移到C塔,但每次只允许移一个盘子,而且在移动过程中始终保持大盘子在下,小盘子在上,在移动过程中可以利用B塔。分析移动步骤递归公式程序代码图5-6汉诺塔问题分析可以用递归的思想来考虑这个问题。假设能将A塔中最上面的n-1个盘子借助于C塔移动到B塔,然后将A塔中剩下的一个盘子移动到C塔,再将B塔中的n-1个盘子借助于A塔移动到C塔,这样问题就解决了。因此接下来就要考虑如果一个塔内有n-1个盘子,如何借助于另一个塔移动到C塔,与n个盘子的思考方法一样,此时可考虑先移动n-2个盘子,依次类推,当变成移动一个盘子时,递归结束。
移动步骤将n个盘子从A塔移到C塔上,可以分解为以下3个步骤:
将A塔上的n-1个盘子借助C塔先移到B塔上;
将A塔上剩下的1个盘子移到C塔上;
将n-1个盘子从B塔借助于A塔移到C塔上。
其中第一步和第三步又可以分解为类似的三步,依次类推,直到A中只剩下一个盘子时,递归结束。
递归公式将k-1个盘子从一个塔借助于另一个塔移动到第三个塔上(k>1),它是一个递归的过程。用函数Hanoi(intk,charA,charB,charC)表示,其中第一个参数k为要移动盘子的个数,第二个参数A为初始塔,第三个参数B为中间塔,第四参数C为目标塔。该函数的功能是将A塔中的k个盘子通过B塔移动到C塔。
将1个盘子从一个塔移到另一塔上。用Move(charA,charB)实现,即将A塔中的盘子移动到B塔中去。
作用域和存储类作用域是指程序中所说明的标识符的适用范围。C++中的作用域共分为:块作用域、文件作用域、函数原型作用域、函数作用域和类作用域。存储类型决定了变量的生存期,即何时为变量分配存储空间以及何时撤消存储空间。在定义变量时,通常根据该变量的不同用途,为其指定相应的存储类型。作用域
存储类型
5.4作用域作用域描述的是标识符起作用的范围,这里的标识符可以泛指变量、常量或函数原型说明等。但对编译预处理中宏定义中的宏名却不适用。
块作用域
函数原型作用域
函数作用域
文件作用域
5.4.1块作用域用花括号括起来的程序段构成一个块(即复合语句),在块内说明的标识符只能在该块内使用,其作用域就称为块作用域。具有块作用域的标识符的有效范围是从声明处开始,到块结束处为止,该作用域的范围是具有局部性的。因此,在块内定义的变量称为局部变量。
示例对于块作用域,C++语言做如下的规定:
块嵌套问题
对一些特殊情况,C++作不同的处理
块嵌套问题块嵌套问题。当块A包含块B,则在块B中可以使用在块A中定义的标识符,反过来则不行。另外当在块A中定义的标识符与块B中定义的标识符同名时,则在块B中的标识符将屏蔽块A中的同名标识符,即局部优先
【例5.8】块嵌套中标识符的使用
对一些特殊情况,C++作不同的处理对if语句或switch语句的表达式中定义的标识符,其作用域在该语句内。例如在for语句的第一个表达式中声明的标识符,其作用域为包含该for循环语句的那个块。例如
定义有参函数时,形式参数的作用域为块作用域,即它的适用范围为整个函数体
例如voidBlock4(){
if(inti=2) //i的作用域从此行开始
i+=1; else i+=2;
//i的作用域到此行结束
cout<<i<<endl; //错误,i没有定义}例如voidBlack5(){ for(inti,j=0;i<10;i++)//A {
intj=9; //与A行定义的j没有冲突,
cout<<i+j<<’\t’; }
inti=10; //错误,与A行定义的i同名
cout<<”i=”<<i<<’\n’; }函数原型作用域函数原型声明(没有函数体)中参数的作用域称为函数原型作用域。此时,参数的作用域开始于函数原型声明的左括号,结束于函数原型声明的右括号。比如:
voidFun(intx,inty); x=2;//错误,x没有定义
由于函数原型声明中的参数名与函数定义以及函数调用均无关,因此,函数原型声明中参数的标识符可以与函数定义中参数的标识符不同,甚至在函数原型声明时可以只列出参数的类型,而没有参数名。比如:
voidFun(int,int);函数作用域函数作用域是指在函数体内定义的标识符在其定义的函数内均有效。该标识符在函数的任何位置都可以使用它,不受先定义后使用的限制,也不受函数体中嵌套块的限制。C++中,只有标号具有函数作用域,即在一个函数体内定义的标号,在该函数的任何位置都可以调用该标号(条件语句、循环语句、switch语句中的特殊情形除外)。且正是由于标号为函数作用域,因此在一个函数中不能用goto语句调用另一个函数中的标号。例如
例如voidFun(intx){
inty;lab1: cout<<”输入y:”<<’\n’;//A
cin>>y;
{ lab1:y+=x;//错误,与A行的标号同名,尽管它们属于不同的块
if(!y)gotolab1; elsegotolab2; //错误,不能调用其它函数中的标号
}}voidFun1(intx){lab2:cout<<x<<’\n’;}文件作用域具有文件作用域的标识符是在所有函数定义之外定义的,即该标识符不隶属于任何块。它的作用域从标识符声明处开始,一直到文件结束。具有文件作用域的变量称为全局变量。当在块作用域内的变量与全局变量同名时,局部变量优先。此时若想在该块中调用全局变量,可通过作用域运算符“::”来实现。
【例5.9】在块作用域内引用文件作用域同名变量
存储类型作用域是从空间上对标识符进行划分的,而存储类型则是从变量存在的时间(即生存期)来划分变量。变量的存储类型可以分为静态存储方式和动态存储方式两大类。
在C++中,变量的存储类型分为四种:自动(auto)类型、寄存器(register)类型、静态(static)类型和外部(extern)类型。
自动类型变量
静态类型变量
寄存器类型变量
外部类型变量
5.4.2静态存储方式
在程序开始执行时就为变量分配存储空间,直到程序执行结束时,才收回为变量分配的存储空间,这种变量称为静态存储变量,其生命期为整个程序执行过程。动态存储方式
在程序的执行过程中,为其分配存储空间的变量称为动态存储变量。对于动态存储变量,当程序运行到该变量的定义处时为其分配存储空间,而当程序运行到该变量所在作用域的结束处时自动收回为其分配的存储空间。因此动态存储类型的变量的生存期为其所在的作用域。
自动类型变量用关键字auto修饰的变量称为自动类型的变量。在说明局部变量时,编译系统默认其为自动类型变量,因此通常省略关键字auto。自动类型的变量只能是局部类型的变量,不可能为全局变量。示例自动类型变量属于动态存储类型变量。上例中的x,y的生存期为其所在的作用域。具体说,对x而言,在A行为其分配4个字节的存储空间,到B行就收回该存储空间。在使用自动类型的变量之前必须对其赋初值。否则,其值为一个不确定的随机数。
autointI;//错误,全局变量不能用关键字 //auto修饰voidAu(void){autointx=1;//Ax为自动类型变量
chary=’a’; //省略关键字auto系统默 //认y为自动类型变量} //B静态类型变量静态存储类型的变量有两种:全局变量和静态类型变量。用关键字static修饰的变量称为静态类型变量。静态类型变量可以为局部变量,也可以为全局变量。静态类型变量属于静态存储变量,即在程序开始运行时就为其分配存储空间,当程序结束时才释放其所占用的存储空间。因此在整个程序执行过程中,静态变量都始终占用同一个存储空间。
【例5.10】使用静态类型的局部变量
寄存器类型变量用关键字register修饰的局部变量称为寄存器类型变量,这类变量也采用动态存储的分配方式。在编译过程中,编译器不为寄存器类型的变量分配内存空间,而是直接使用CPU中的寄存器,以便提高对这类变量的存取速度。寄存器类型变量主要用于控制循环次数等不需要长期保存值的变量。
【例5.11】利用寄存器类型变量求l~15的阶乘。
#include<iostream.h>voidmain(void){ registerfloatFact=1; //定义实型寄存器变量Fact for(registerinti=1;i<=15;i++)//定义整型寄存器变量i { Fact*=i;
cout<<i<<"!="<<Fact<<'\n'; }}外部类型变量用关键字extern修饰的变量称为外部类型变量,外部类型变量必须是全局变量。在C++中,有两种情况下需要使用外部类型变量。
在同一个源程序文件中,当在全局变量的定义之前使用该变量时,在使用前要对该变量进行外部类型变量声明。【例5.12】外部类型变量的声明
当程序由多个文件组成时,若在一个源程序文件中要引用在另一个源程序中定义的全局变量,在引用前必须对所引用的变量进行外部声明。【例5.13】文件间共享全局变量
【例5.12】外部类型变量的声明#include<iostream.h>int
Max(int
x,inty){returnx>y?x:y;}
voidmain(void){ externinta,b; //A
cout<<Max(a,b); //B}inta=12,b=-4;【例5.13】文件间共享全局变量externfloatx; //A voidmain(void) { x++;cout<<x<<’\n’;}在文件c2.cpp中有:
floatx=100; //B
…
内联函数一般函数在调用时,要花费将实参和返回地址压入栈,然后转入执行被调用函数等一系列开销。
C++中的内联函数,将省略这类的开销。编译系统对内联函数的处理与一般函数的处理方式不同,在编译调用内联函数的语句时,编译器将内联函数的代码插入到函数调用处,在运行过程中,将直接运行插入的代码,从而可以提高程序运行的速度。将一个函数声明为内联函数时,只要在函数定义前加关键字inline即可,声明格式【例5.14】用内联函数计算立方体的体积
5.5内联函数声明格式
inline<类型><函数名>(《参数表》) {
…//函数体
}【例5.14】用内联函数计算立方体的体积#include<iostream.h> inlinefloatCube(floata){returna*a*a;}
voidmain(){
cout<<”输入立方体的边长:”; floatside;
cin>>side;
cout<<”边长为”<<side<<”的立方体的体积为:”
<<Cube(side)<<’\n’; //A}具有缺省参数值的函数在定义具有缺省参数值的函数时,要为参数指定一个值。比如:
voidFun(intx=1,inty=2){…}【例5.15】具有缺省参数值的延时函数
【例5.16】求圆柱体的体积
5.6【例5.15】具有缺省参数值的延时函数#include<iostream.h>voidDelay(intn=1000) //A{ for(;n>0;n--); }
voidmain(void){cout<<"延时500个单位时间…\n";Delay(500); //Bcout<<"延时1000个单位时间…\n";Delay(); //C}【例5.16】求圆柱体的体积#include<iostream.h>#definePI3.1415926floatVolume(floatr,floath=10); //A
voidmain(void){ floatr,h;
cout<<"输入第一个圆柱体的半径和高度:";
cin>>r>>h;
cout<<"第一个圆柱体的体积为:"<<Volume(r,h)<<'\n';
cout<<"输入第二个圆柱体的半径:";
cin>>r;
cout<<"第二个圆柱体的体积为:"<<Volume(r)<<'\n'; floatVolume(float=5,float=20); //B
cout<<"第三个圆柱体的体积为:"<<Volume()<<'\n';//C}floatVolume(floatr,floath) //D { return(PI*r*r*h); }函数重载函数的重载又称函数名重载,是指实现不同功能的函数可以具有相同的函数名。
C++编译器在进行函数调用时是根据函数名和函数的参数来决定调用哪一个函数的,因此,对于函数名重载问题,要区分函数名相同的函数,只有从它们的参数上进行区分。要实现函数名重载,它们的参数必须满足下面两个条件之一:参数的个数不同参数的类型不同【例5.17】利用参数类型的不同实现重载函数
【例5.18】利用参数个数不相同实现重载函数在定义重载函数时要注意的几点
5.7【例5.17】利用参数类型的不同实现重载函数#include<iostream.h>
int
Abs(intx){ //A
cout<<”调用函数Abs(int).”<<’\n’; returnx>=0?x:-x; } doubleAbs(doublex) { //B
cout<<”调用函数Abs(double).”<<’\n’; returnx>=0?x:-x; } voidmain() {
cout<<”-20的绝对值是:”<<Abs(-20)<<endl;//C
cout<<”-111.11的绝对值是:”<<Abs(-111.11)<<endl;//D }【例5.18】利用参数个数不相同实现重载函数#include<iostream.h>int
max(int
a,intb);int
max(int
a,int
b,intc);int
max(int
a,int
b,int
c,intd);voidmain(){
cout<<max(3,5)<<endl;
cout<<max(-7,9,0)<<endl;
cout<<max(23,15,3,6)<<endl; }int
max(int
a,intb){ returna>b?a:b;}int
max(int
a,int
b,intc){ intt=max(a,b); returnmax(t,c);}int
max(int
a,int
b,int
c,intd){ intt1=max(a,b);
intt2=max(c,d); returnmax(t1,t2);}在定义重载函数时要注意的几点定义的重载函数必须具有不同的参数个数或不同的参数类型,只有这样编译系统才能根据不同的参数决定调用哪一个函数版本
仅仅是函数返回值不同并不能区分两个函数,因此不能根据函数的返回值定义函数的重载。例如
int
sum(inta){…}voidsun(inta) {…}这两个函数仅仅返回值不同,编译时将发生二义性错误。编译预处理C++语言中使用一些特殊的命令,在编译之前先对这些命令进行“预处理”,然后将结果和源程序一起进行编译处理,得到目标代码,此过程称为编译预处理。这些命令称为编译预处理指令,它们不是C++语句,一律以#开头,以回车符结束,每一条预处理指令独占一行。
根据编译预处理功能的不同,将其分为三类:宏定义#define、文件包含#include和条件编译#if。
“文件包含”处理
宏定义
条件编译
5.8所谓“文件包含”处理是指一个源文件可以将另一个源文件的全部内容包含进来。“文件包含”可通过#include编译预处理指令来实现,格式为:
#include<文件名>或
#include“文件名”
“文件包含”的处理过程
【例5.19】文件包含的应用
关于#include编译预处理指令需要说明的几点
“文件包含”处理5.8.1这种格式是标准格式,主要用于包含C++系统所提供的头文件。当C++预处理器遇到该指令时,就到C++系统目录的include子目录下搜索给出的文件,并把它嵌入到当前文件中。
这种格式既适合于用户自己建立的文件,也适合于C++系统提供的头文件。当C++预处理器遇到该指令后,首先在当前工作目录中查找所包含的文件,如果找不到,再按标准方式进行搜索。
“文件包含”的处理过程包含#include“File2.h”ABBAFile1.cppFile2.hFile1.cpp(a)(b)(c)图3-7“文件包含”示意图编译预处理【例5.19】文件包含的应用设文件File1.h的内容为:intx=200,y=100; floatx1=25.6,x2=28.9;设文件File2.cpp的内容为:#include“File1.h”//A#include<iostream.h>voidmain(void) { cout<<x<<’\t’<<y<<’\n’;
cout<<x1<’\t’<<x2<<’\n’; }intx=200,y=100;floatx1=25.6,x2=28.9;#include<iostream.h>voidmain(void){cout<<x<<’\t’<<y<<’\n’;
cout<<x1<<’\t’<<x2<<’\n’;}关于#include编译预处理指令需要说明的几点被包含的文件通常是头文件,也可以为其他类型的文件,如源程序文件或文本文件等;
一个#include命令只能指定一个被包含文件;一个被包含的文件中也可以包含其他文件,即文件的包含可以是嵌套的,嵌套的层次也没有限制;
#include指令可以出现在程序中的任何位置,通常是放在程序的开头
由于被包含的文件(File1.h)与其所在的文件(File2.cpp)在预编译后已称为合并到一个文件中,因此,File2.cpp可直接访问File1.h中的全局变量,此时可不用extern声明。同样,File2.cpp中也能直接访问File1.h中的函数
宏定义
宏定义用#define编译预处理指令实现,可分为不带参数的宏定义和带参数的宏定义。不带参数的宏常用于定义标识符常量,即可将一个常量指定给一个标识符,它与const类型的变量类似;带参数的宏可将一个表达式指定给一个带参数的标识符,它与函数的功能类似。
不带参数的宏定义
【例5.20】不带参数的宏的使用
带参数的宏定义
【例5.21】带参数的宏定义的使用
5.8.2不带参数的宏定义定义不带参数宏的一般格式为:
#define标识符
字符序列
其中标识符称为宏名,它可以是任意合法的标识符,通常为大写。字符序列为一串字符,它可由任意的字符构成,包括空格。例如:
#definePI3.1415926不带参数的宏定义及其使用需说明的几点
不带参数的宏定义及其使用需说明的几点宏名可以为任意的合法标识符,常用大写字母表示
宏定义中可以用已定义过的宏名,但对用双引号括起来的字符序列中的字符,即使与宏名相同,也不进行宏扩展。例如
宏扩展时,只对宏名作简单的代换,不作任何计算,也不作任何语法检查;比如宏定义不是C++语句,不必在行末加分号,如果加了分号则会连分号一起进行宏扩展,例如:一个宏通常在一行内定义完,并以换行符结束。当多于一行时,须使用转义字符“
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025民间的借款合同范本2
- 2025搬家货运合同模板
- 2025年度年度水利工程设施维修管理协议3篇
- 二零二五年度2025年农业合作社合伙人合同协议3篇
- 2025年度农村房屋买卖合同(含房屋附属设施及土地开发)
- 二零二五年度农村住房建设智能化系统安装合同
- 2025年度大学毕业生就业意向与培养协议3篇
- 2025年度出差环境保护与可持续发展协议3篇
- 二零二五年度新型农村机井承包管理协议
- 2025年度体育用品商铺租赁合同范本(含赛事赞助合作)3篇
- 中央企业人工智能应用场景案例白皮书(2024年版)-中央企业人工智能协同创新平台
- 江苏省苏州市2024-2025学年第一学期八年级历史期末模拟卷(二)(含答案)
- 杜瓦瓶充装操作规程(3篇)
- 甘肃兰州生物制品研究所笔试题库
- 医院改扩建工程可行性研究报告(论证后)
- 双方共同招工协议书(2篇)
- 2021-2022学年第二学期《大学生职业发展与就业指导2》学习通超星期末考试答案章节答案2024年
- 国家开放大学电大本科《工程经济与管理》2023-2024期末试题及答案(试卷代号:1141)
- 客车交通安全培训课件
- 医院劳务外包服务方案(技术方案)
- 张克非《公共关系学》(修订版)笔记和课后习题详解
评论
0/150
提交评论