预处理,概述,  在后面各章中,已屡次运用过以“#”号开头的预处理饬令。如包孕饬令#include,宏定义饬令#define等。在源法度中这些饬令都放在函数之外,而且伟大都放在源文件的后面,它们称为




预处理

概述

  在后面各章中,已屡次运用过以“#”号开头的预处理饬令。如包孕饬令# include,宏定义饬令# define等。在源法度中这些饬令都放在函数之外, 而且伟大都放在源文件的后面,它们称为预处理部门。


  所谓预处理是指在中缀编译的第一遍扫描(词法扫描和语法分析)之前所作的事故。预处理是C说话的一个首要听命, 它由预处理法度卖力完成。当对一个源文件中缀编译时, 系统把主动援用预处理法度对源法度中的预处理部门作处理, 处理截止主动进入对源法度的编译。


  C说话提供了多种预处理听命,如宏定义、文件包孕、 前提编译等。公正地运用预处理听命编写的法度便于阅读、编削、 移植和调试,也有利于模块化法度计划。本章引见常用的几种预处理听命。


宏定义

  在C说话源法度中允许用一个标识符来走漏显示一个字符串, 称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对法度中扫数泛起的“宏名”,都用宏定义中的字符串去代换, 这称为“宏代换”或“宏睁开”。


  宏定义是由源法度中的宏定义饬令完成的。 宏代换是由预处理法度主动完成的。在C说话中,“宏”分为有参数和无参数两种。 上面告别讨论这两种“宏”的定义和调用。


无参宏定义

  无参宏的宏名后不带参数。其定义的伟大方法为: #define 标识符 字符串 其中的“#”走漏显示这是一条预处理饬令。平常以“#”开头的均为预处理饬令。“define”为宏定义饬令。 “标识符”为所定义的宏名。“字符串”可以是常数、表达式、样式串等。在后面引见过的符号常量的定义就是一种无参宏定义。 别的,常对法度中几回运用的表达式中缀宏定义。例如: # define M (y*y 3*y) 定义M表达式(y*y 3*y)。在编写源法度时,扫数的(y*y 3*y)都可由M庖代,而对源法度作编译时,把先由预处理法度中缀宏代换,即用(y*y 3*y)表达式去置换扫数的宏名M,然后再中缀编译。

#define M (y*y 3*y)

main(){

int s,y;

printf("input a number: ");

scanf("%d",&y);

s=3*M 4*M 5*M;

printf("s=%d\n",s);

}

  上例法度中起首辈行宏定义,定义M表达式(y*y 3*y),在s= 3*M 4*M 5* M中作了宏调用。在预处理时经宏睁开后该语句变为:s=3*(y*y 3*y) 4(y*y 3*y) 5(y*y 3*y);但要详细的是,在宏定义中表达式(y*y 3*y)单方的括号不克不及少。不然会发生发火错误。

  当作以下定义后: #difine M y*y 3*y在宏睁开时把失踪失踪下述语句: s=3*y*y 3*y 4*y*y 3*y 5*y*y 3*y;这相称于; 3y2 3y 4y2 3y 5y2 3y;显然与原题意要求不符。计较成就虽然是错误的。 是以在作宏定义时必需很是详细。应保证在宏代换之后不发生发火错误。关于宏定义还要说明');以下几点:


1. 宏定义是用宏名来走漏显示一个字符串,在宏睁开时又以该字符串庖代宏名,这只是一种简略的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理法度对它不作任何搜查。如有错误,只能在编译已被宏睁开后的源法度时发明。


2. 宏定义不是说明');或语句,外行末不用加分号,如加上分号则连分号也一同置换。


3. 宏定义必需写在函数之外,其感导域为宏定义饬令起到源法度结 束。如要中缀其感导域可运用# undef饬令,例如: # define PI 3.14159

main()

{

……

}

# undef PIPI的感导域

f1()

....走漏显示PI只在main函数中有效,在f1中有效。

4. 宏名在源法度中若用引号括起来,则预处理法度分歧错误其作宏代换。

#define OK 100

main()

{

printf("OK");

printf("\n");

}

上例中定义宏名OK走漏显示100,但在printf语句中OK被引号括起来,是以不作宏代换。法度的运转成就为:OK这走漏显示把“OK”当字符串处理。


5. 宏定义允许嵌套,在宏定义的字符串中可以运用已经定义的宏名。在宏睁开时由预处理法度层层代换。例如: #define PI 3.1415926

#define S PI*y*y /* PI是已定义的宏名*/对语句: printf("%f",s);在宏代换后变为: printf("%f",3.1415926*y*y);


6. 习气上宏名用大写字母走漏显示,以便于与变量区别。但也允许用小写字母。


7. 可用宏定义走漏显示数据范例,使誊写利便。例如: #define STU struct stu在法度中可用STU作变量说明');: STU body[5],*p;#define INTEGER int 在法度中即可用INTEGER作整型变量说明');: INTEGER a,b; 应详细用宏定义走漏显示数据范例和用typedef定义数听说明');符的区别。宏定义只是简略的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简略的代换, 而是对范例说明');符重新命名。被命名的标识符具有范例定义说明');的听命。请看上面的例子: #define PIN1 int* typedef (int*) PIN2;从方法上看这两者相似, 但在幻想运用中却不相反。上面用PIN1,PIN2说明');变量时就可以看出它们的区别: PIN1 a,b;在宏代换后酿成 int *a,b;走漏显示a是指向整型的指针变量,而b是整型变量。但是:PIN2 a,b;走漏显示a,b都是指向整型的指针变量。因为PIN2是一个范例说明');符。由这个例子可见,宏定义虽然也可走漏显示数据范例, 但毕竟是作字符

代换。在运用时要非分不凡小心,以避蜕化。


8. 对“输入样式”作宏定义,可以增长誊写费事。例9.3 中就回收了这种举措。

#define P printf

#define D "%d\n"

#define F "%f\n"

main(){

int a=5, c=8, e=11;

float b=3.8, d=9.7, f=21.08;

P(D F,a,b);

P(D F,c,d);

P(D F,e,f);

}





版权声明: 原创作品,允许转载,转载时请务必以超链接方法标明文章 原始因由 、作者信息和本声明。不然将清查划定规矩责任。