nullnull 第八章 编译预处理本章要点:
了解预处理的概念及特点
掌握有参宏与无参宏的定义及使用
理解文件包含的使用及效果
了解条件编译null运行结果如:实例 8.1 宏定义
一、 不带参数的宏定义
作用: 用一个指定的标识符来代
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
一个字符串
格式: #define 标识符 字符串
这种标识符也叫“宏名”,将宏名替换成字符串的过程叫 “ 宏展开 ”。#define PI 3.1415926一#define PI 3.1415926
main ( )
{ float l , s , r , v ;
printf ( “ input radius : ” ) ;
scanf ( “%f ” , &r ) ;
l = 2.0 * PI * r ;
s = PI * r * r ;
v = 3.0/4 * PI * r * r * r ;
printf ( “ l = %10.4f\n s=%10.4f\n v=%10.4f\n”, l , s ,v ) ;
}例结果input radius : 4
l = 25.1328
s = 50.2655
v = 150.7966null一、 不带参数的宏定义的几点
说明
关于失联党员情况说明岗位说明总经理岗位说明书会计岗位说明书行政主管岗位说明书
1. 宏名一般大写,以区别于变量名。2. 宏定义只是简单替换,不作语法检查。如3. 宏定义不是 C 语句,不能乱加分如4. 宏名的有效范围是从定义点到本源文件结束。 但 也可用 #undef 命令来终止宏名的作用域。如5. 宏定义可以层层置换,即在宏定义时可以引用已定义过的宏名。例6. 对程序中用双引号括起来的字符串内的字符,即使与宏名相同,也不置换。例i #define PI 3.1415926 #define PI 3.l415926
预处理时照常带入,只是在编译已被宏展开的源 程序时才报错。例#define PI 3.1415926 ;
……
area = PI * r * r ;
宏展开后:
area = 3.1415926 ; * r * r ;#define G 9.8
main ( )
{ ……. }
#undef G
f1 ( )
{ …… }
重点例 8.2
#define R 3.0
#define PI 3.1415926
#define L 2 * PI * R
#define S PI * R * R
void main ( )
{
printf (“ L = %f\n S = %f\n”, L , S ) ;
}
经过宏展开后:
printf ( “L = %f\n S = %f\n ” , 2 * 3.1415926 * 3.0 ,
3.1415926 * 3.0 * 3.0 ) ;例null替换规则:二、带参数的宏定义
作用: 进行字符串和参数的替换
格式: #define 宏名(参数表) 字符串
例如 程序示例说明
1.宏的参数可以是常量,变量或表达式。对表达式 应注意加适当的括号。 如
2.定义时宏名与带参的括号之间不能有空格。否则 变成无参的宏定义。如例如例 如果程序中有带实参的宏,则按 #define 命令中指定的字符串从左至右进行置换。串中如包含有宏中的参数,则将程序语句中相应的实参代替形参,如字符串中的字符不是参数字符,则保留。规则 在例8.3 中改成:
area = S( a + b ) ; 则宏展开后为:
area = PI * a + b * a + b (不合本意)
改成: #define S( r ) PI * (r) *(r)
则:
S( a + b ) 宏展开成 PI * (a + b) * ( a + b ) ; 重点 如:
# define Sᗻ( r )ᗻᗻPI *( r ) * ( r )
……
则: area = Sᗻ( a ) ;
宏展开成:
area = ( r )ᗻᗻPI *( r ) * ( r )ᗻ( a ) ; 重点null三、带参数的宏与函数的区别
1.函数调用时要先求实参表达式的值,然后带入形参。而带参的宏只是进行替换。 如: S( a + b ) ,在宏展开 时并不求 a + b 的值。
2.函数调用是在程序运行时处理的,要分配临时内存单元。而宏展开是在编译时进行的。且展开时不分配内
存单元。也无返回值和值传递的概念。
3. 函数中存在实参和形参的类型问题,而宏不存在类
型问题,因为宏名不是变量。
如: #define CHAR1 CHINA ( 字符 )
#define a 3.6 ( 数值 )
4.一般情况下函数调用只能得到一个返回值。而用宏可
以设法获得几个结果。null例 8.4
#define PI 3.1415926
#define CIRCLE(R ,L , S ,V) L= 2*PI*R ; S = PI*R*R ;
V = 4.0/3.0 * PI * R * R * R
main ( )
{ float r , l , s , v ;
scanf ( “ %f ”, &r ) ;
CIRCLE ( r , l , s ,v ) ;
printf ( “ r = % 6.2f , l = 6.2f , s = %6.2f , v = %6.2f \n”,
r , l , s , v ) ;
}
经预编译宏展开后的程序如下:null main ( )
{ float r , l , s , v ;
scanf ( “ %f ”, &r ) ;
l = 2 * 3.1415926 * r ; s = 3.1415926 * r * r ;
v = 4.0/3.0 * 3.1415926 * r * r * r ;
printf ( “ r = % 6.2f , l = 6.2f , s = %6.2f , v = %6.2f\n ”,
r , l , s , v ) ;
}
输入: 3.5
输出: r = 3.50 , l = 21.99 , s = 38.48 , v = 179.59
5. 宏替换只占用编译时间,不占用运行时间。而函数
调用则要占用运行时间。null有些问题用宏和函数都可以。如:
#define MAX( x , y ) ( x ) > ( y ) ? ( x ) : ( y )
……
main ( )
{ int a , b , c , d , t ;
……
t = MAX( a + b , c + d ) ;
……
}
赋值语句展开后:
t = (a + b) > ( c+d ) ? ( a+b ) : (c+d ) ; null int max ( int x , int y )
{ return ( x > y ? x : y ) ;
}
main ( )
{ int a , b , c , d , t ;
……
t = max ( a + b , c + d ) ;
……
}
例 8.5
#define PR printf
#define NL “ \n ”
#define D “ %d ”null #define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S “ %s ”
main ( )
{ int a , b , c , d ;
static char string[ ] = “ CHINA” ;
a = 1 ; b = 2 ; c = 3 ; d = 4 ;
PR ( D1 , a ) ; printf ( “ %d ” “\n” , a ) ;
PR ( D2 , a , b ); printf ( “ %d ” “ %d ” “\n” , a ,b) ;
PR ( D3 , a , b , c ) ;
PR ( D4 , a , b , c , d ) ;
PR ( S , string ) ; }null 输出结果 : 1
1 2
1 2 3
1 2 3 4
CHINA
6. 在实参替换时,对双引号内字符串中与参数名相同的字符是否被替换随C系统有所不同。 如 Turbo C 中不
替换。而VAX等一些中小型机使用的C系统则要替换。
例 8.6
#define PRINT ( V ) printf( “ V = %d \t ”, V )
main( )
{ int a , b ; a = 1 ; b = 2 ;
PRINT ( a ) ; PRINT ( b ) ;
} printf( “ a = %d \t ”, a)
printf( “ V = %d \t ”, a)null 希望输出的结果: a = 1 b = 2
实际输出的结果: V = 1 V = 2
例 8.7
#define NL printf ( “\n” )
#define PRINT ( F , V ) printf ( “V= %F \t ”, V )
#define PRINT1 ( F , X1 ) PRINT ( F, X1) ; NL
#define PRINT2 ( F , X1, X2 ) PRINT ( F, X1) ;
PRINT ( F, X2) ; NL
main ( )
{ int a , b , c , d ;
float e , f , g , h ;
long i , j ;
char n , m ;null a = 1 ; b = 2 ; c = 4 ; e = 1.5 ; f = 2.5 ; g = 3.5; h = 4.5 ;
i = 10 ; j = 100 ; n = ‘ X ’ ; m = ‘ Y ’ ;
PRINT ( d , a ) ; printf ( “ V = %F\t ”, a ) ;
PRINT1 ( d , a ) ; printf (“V = %F\t”, a ) ; printf (“\n”) ;
PRINT2 ( d , a , b ) ;
PRINT2 ( d , c , d ) ;
PRINT2 ( f , e , f ) ;
PRINT2 (f , g , f ) ;
PRINT2 (f , g , h ) ;
PRINT2 (ld , i , j ) ;
PRINT2 (c , n , m ) ;
}
输出: V = % F V = % F
V = % F V = % F
V = % F V = % FPRINT ( F, X1) ;
PINT ( F, X2) ; NL
printf ( “ V = %F \t ”, a ) ;
printf ( “ V = %F \t ”, b ) ;
printf (“\n”) ; null§8.2 “文件包含 ” 处理
文件包含是将另一个 C 源文件的全部内容包括进一个
指定的 C 源文件
格式 : #include “ 文件名 ”
或 #include < 文件名 >
A file1.cB file2.cAB file1.c包含null 如: 例 8.5 的程序可以改为:
format . h 文件
#define PR printf
#define NL “ \n ”
#define D “ %d ”
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S “ %s ”null(2) file1.c 文件
#include “format . h ”
void main ( )
{
int a , b , c , d ;
static char string[ ] = “ CHINA” ;
a = 1 ; b = 2 ; c = 3 ; d = 4 ;
PR ( D1 , a ) ;
PR ( D2 , a , b ) ;
PR ( D3 , a , b , c ) ;
PR ( D4 , a , b , c , d ) ;
PR ( S , string ) ;
}
null说明:
1. 一个 include 命令只能指定一个被包含文件.
2. 如 file1.c要包含 file2.c ,而 file2.c 要包含 file3.c , 则在 file1.c 中可用两条 include 命令. 如:
#include “ file3.c ”
#include “ file2.c ” (注意包含顺序)
3. 文件包含可以嵌套 示意图
4. 文件包含可以指定盘符和路径
如: #include “ a:\ ww \ format . h ”图null§8.3 条件编译
1. #ifdef 标识符
程序段 1
#else
程序段 2
#endif
2. #ifndef 标识符
程序段 1
#else
程序段 2
#endif
3. #if 表达式
程序段 1
#else
程序段 2
#endif
也可:#ifdef 标识符
程序段 1
#endifnull 例 8.8
#define LETTER 1
main ( )
{ static char str[20] = “ C Language ” , c ;
int i = 0 ;
while (( c = str[i] ) ! = ‘\0’ )
{ i + + ;
#if LETTER
if ( c > = ‘a’ && c < = ‘z’ )
c = c – 32 ;
#else
if ( c > = ‘A’ && c < = ‘Z’ )
c = c + 32 ;
#endif
printf ( “ %c ”, c ) ; } }C LANGUAGEnull 补充例题:以下程序的输出结果是
#include “stdio.h”
#define FUN( y ) 2.84 + y
#define PR( a ) printf( “%d ” , (int)(a) )
#define PRINT( a ) PR( a ) ; putchar( ‘\n’ )
main( )
{ int x = 2 ;
PRINT( FUN(5) * x ) ;
} 12PR( a ) ; putchar( ‘\n’ ) ;
printf ( “ %d ” , ( int ) ( FUN(5) * x )) ;
printf ( “ %d ” , ( int ) ( 2.84 + 5 * x )) ;null作业:9.1 9.6 9.10