预处理

如:#include<stdio.h>,宏定义命令#define PI 3.14 等。

在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分。

1、无参宏定义

无参宏的宏名后不带参数。

其定义的一般形式为:#define 标识符 字符串

其中“#”表示这是一条预处理命令。

define为宏定义命令。“标识符“为所定义的宏名。”字符串“可以是常数,表达式,格式串等。

例:#define PI 3.14

它的作用是指定标识符PI来代替数3.14。

在编写源程序时,所有的3.14都可以用PI来代替,而对源程序做编译时,将先有预处理程序做宏代换,即用3.14表达式去置换所有的宏名PI,然后再进行编译。

例:

#include<stdio.h>
#include "StdAfx.h"
#define PI 3.14
void main()
{
    double s;
    int r;
    scanf("%d",&r);
    s=r*r*PI;
    printf("%g\n",s);
}

说明:(1)宏命令是在一种简单的代换,字符串中可以是任何字符,常量或表达。预处理程序不会做任何检查,若有错误,只能在编译已被宏展开的源程序时发现。

(2)宏命令不是说明或语句,不必加分号,若加分号,则连分号也一并置换。

(3)宏命令必须写在函数之外,其作用域为宏定义命令起到源程序结束,如要终止其作用域可使用#undef命令。

(4)宏名在源程序中若用引号括起,则预处理程序不对其作宏代换。

例:

#include<stdio.h>
#include "StdAfx.h"
#define PI 3.14
void main()
{
    void fun(void);
    double s;
    int r;
    scanf("%d",&r);
    s=r*r*PI;
    printf("%g\n",s);
    fun();
}
void fun(void)
{
    printf("PI=%g\n",PI);
    printf("PI\n\n");
}

(5)宏定义允许嵌套,在宏定义的字符串中可以使用已定义的宏名。在宏展开时有预处理程序层层代换。

(6)习惯上宏名用大写字母表示,以便于与变量区别,但也允许小写字母。

(7)可用宏定义表示数据类型,使书写方便。

例:#define INTEGER int 

注:宏定义表示数据类型和typedef定义数据说明符的区别:宏定义是简单的字符串代换,是在预处理完成的,它不是简单的代换,而是对类型说明符重命名。被命令的标识符具有类型定义说明的功能。

例:

#include<stdio.h>
#include "StdAfx.h"
#define PIN1 char*
typedef char*PIN2;
void main()
{
    PIN1 x,y;
    PIN2 a,b;
    printf("#define:%d %d\n\n",sizeof(x).sizeof(y));
    printf("typedef:%d %d\n\n",sizeof(a),sizeof(b));
}

(8)对“输出格式”做宏定义,可以减少书写的麻烦。

例:

#include<stdio.h>
#include "StdAfx.h"
#define P printf
#define D "%d\n"
#define F "%f\n"
void main()
{
    int a=5,c=8,e=11;
    float b=3.8,d=9.1,f=21.08;
    P(D F,a,b);
    P(D F,c,d);
    P(D F,e,f);

}

2、带参宏定义

C中允许宏带有参数,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。

对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

定义的一般形式为:#define 宏名(形参表)字符串

调用的一般形式为:宏名(实参表);

例:#define M(y) y*y+3*y     /*宏定义*/

  ……

  K=M(5)         /*宏调用*/

  ……

在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5*+3*5;

例:

#include<stdio.h>
#include "StdAfx.h"
#define MAX(a,b) (a>b)?a:b
void main()
{
    int x,y,max;
    scanf("%d%d",&x,&y);
    max=MAX(x,y);
    printf("The max is %d\n",max);
}

注:(1)在带参宏定义中,宏名和形参表之间不能有空格出现。

(2)在带参宏定义中,形参不分配内存单元,因此不必做类型定义,而宏调用中的实参有具体的值,要用他们去代换形参,因此必须要做类型说明。刺出与函数不同,函数调用时进行的是“值传递”,而在带宏参数中,只是符号代换,不存在值传递问题。

(3)在宏定义中形参是标识符,在宏调用中实参是表达式。

例:

#include<stdio.h>
#include "StdAfx.h"
#define SAY(y) (y)^(y)
void main()
{
    int i=0;
    char say[]={73,72,58,65,101,100,45,100,78};
    while(say[i])
    {
        say[i]=SAY(say[i])^say[i];
        i++;
    }
    printf("%s\n",say);
}

(4)在宏定义中,字符串内的形参通常用括号括起来以避免出错。

例:

#include<stdio.h>
#include "StdAfx.h"
#define SQ(y) (y)*(y)
void main()
{
    int a,sq;
    printf("input a number:");
    scanf("%d",&a);
    sq=160/SQ(a+1);
    printf("sq=%d\n",sq);
}

(5)带参宏与带参函数很相似,但本质上是不同的,同一表达式的处理与用宏处理两者的结果有可能是不同的。

(6)宏定义也可用来定义多个语句,在宏调用时又把这些语句代换到程序内。

例:

#include "StdAfx.h"
#include<stdio.h>
#include<string.h>

#define STR(s1,s2,s3,sum) strcat(strcat(strcat(sum,s1),s2),s3);
void main()
{
    char str1[]="I",str2[]="love",str3[]="China",str[40]="";
    STR(str1,str2,str3,str);
    printf("\n\tstr1=%s\n\tstr2=%s\n\tstr3=%s\n\tstr=%s\n",str1,str2,str3,str);
}

 

posted @ 2019-02-13 19:37  巫师笔记  阅读(271)  评论(0编辑  收藏  举报