第09章 C语言预处理命令
C语言中级教材培训课程—预处理
C 语言中级培训预处理的概念编译前编译预处理器语言中,以“#”开头的语句统称为编译预处理命令。
以“#”开始,末尾这些命令必须在一行的开头以“#”开始,末尾不加分号,并且每条命令独占一行不加分号,并且每条命令独占一行,以区别于一为什么要用” 预处理”最小原则丁”的方式,由语言之外的预处理命令或函数提供。
就连处理预处理命令的预处理器C语言的预处理命令“预处理”前的预处理//有的系统是/ ,如VC++什么是宏#define PI (3.1415926)宏定义指令宏名字符串宏定义为什么要用宏定义-文字名称比数字要容易理解得多,一个好的宏名可以望文知义。
120使用宏的弊端:使用宏定义时需要注意的要点:宏替换的弊端:#define PF(x)x*x()()()/*#define PF(x)(x)*(x)*//*#define PF(x)((x)*(x))*/main()注意替换时不求值,{只是字符串的原样替换int a=2,b=3,c;c=PF(a+b)/PF(a+1);printf("\nc=%d",c);}按第一种宏定义:c=a+b*a+b/a+1*a+1;按第二种宏定义:()()()();c=(a+b)*(a+b)/(a+1)*(a+1)按第三种宏定义:c=((a+b)*(a+b))/((a+1)*(a+1));多用括号就万事大吉了吗?2:在定义宏时不要为宏加分号。
#define assert(e)\续行符#define assert(e) \宏定义实例——无参宏定义举例宏定义实例——带参数的宏定义举例宏定义实例——用宏定义构建机制#ifdef AFXDLL #ifdef _AFXDLL{0000AfxSig end(AFX PMSG)0}\ {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \函数调用和宏定义的区别宏定义和类型定义的区别struct student*struct student *st uct stude t请分析下面语句的含义(*((UINT1*)(_data_)))定义了一个带参宏,它能将参数强转成无符号字符类型的地址,再将该地址中的值取出。
c语言的预处理指令分3种 1宏定义 2条件编译 3文件包含
c语⾔的预处理指令分3种 1宏定义 2条件编译 3⽂件包含宏简介1.C语⾔在对源程序进⾏编译之前,会先对⼀些特殊的预处理指令作解释(⽐如之前使⽤的#include⽂件包含指令),产⽣⼀个新的源程序(这个过程称为编译预处理),之后再进⾏通常的编译所有的预处理指令都是以#开头,并且结尾不⽤分号2.预处理指令分3种 1> 宏定义 2> 条件编译 3> ⽂件包含3.预处理指令在代码翻译成0和1之前执⾏4.预处理的位置是随便写的5.预处理指令的作⽤域:从编写指令的那⼀⾏开始,⼀直到⽂件结尾,可以⽤#undef取消宏定义的作⽤6.宏名⼀般⽤⼤写或者以k开头,变量名⼀般⽤⼩写 宏定义可以分为2种:不带参数的宏定义和带参数的宏定义。
⼀、不带参数的宏定义1.⼀般形式#define 宏名字符串⽐如#define ABC 10右边的字符串也可以省略,⽐如#define ABC2.作⽤它的作⽤是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常⽤来定义常量.3.使⽤习惯与注意1> 宏名⼀般⽤⼤写字母,以便与变量名区别开来,但⽤⼩写也没有语法错误2> 对程序中⽤双引号扩起来的字符串内的字符,不进⾏宏的替换操作。
3> 在编译预处理⽤字符串替换宏名时,不作语法检查,只是简单的字符串替换。
只有在编译的时候才对已经展开宏名的源程序进⾏语法检查4> 宏名的有效范围是从定义位置到⽂件结束。
如果需要终⽌宏定义的作⽤域,可以⽤#undef命令5> 定义⼀个宏时可以引⽤已经定义的宏名#define R 3.0#define PI 3.14#define L 2*PI*R#define S PI*R*R举例1 #include <stdio.h>2#define COUNT 434int main()5 {6char *name = "COUNT";78 printf("%s\n", name);910int ages[COUNT] = {1, 2, 67, 89};1112#define kCount 41314for ( int i = 0; i<COUNT; i++) {15 printf("%d\n", ages[i]);16 }1718// 从这⾏开始,COUNT这个宏就失效19#undef COUNT2021//int a = COUNT 写这个报错2223return0;24 }⼆、带参数的宏定义1.⼀般形式#define 宏名(参数列表) 字符串2.作⽤在编译预处理时,将源程序中所有宏名替换成字符串,并且将字符串中的参数⽤宏名右边参数列表中的参数替换3.使⽤注意1> 宏名和参数列表之间不能有空格,否则空格后⾯的所有字符串都作为替换的字符串2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进⾏任何计算操作。
c语言程序中的预编译命令
c语言程序中的预编译命令预编译命令是在编译之前就交由编译器进行相关处理的指令,通常以"#"开头。
预编译命令在整个程序开始编译之前就已经执行。
以下是一些常用的预编译命令:1. #include:用于引入头文件。
例如:```C#include <stdio.h> //引入标准输入输出头文件#include "myheader.h" //引入自定义头文件myheader.h```2. #define:用于定义宏。
例如:```C#define PI 3.14159 //定义宏PI,宏的值是3.14159```3. #undef:用于取消之前定义的宏。
例如:```C#undef PI //取消之前定义的宏PI```4. #ifdef,#ifndef,#endif:用于条件编译。
例如:```C#ifdef PI// 如果宏PI已被定义,则编译以下代码#endif#ifndef PI// 如果宏PI未被定义,则编译以下代码#endif```5. #if, #else, #elif:也是用于条件编译。
例如:```C#if defined(PI)//如果宏PI已被定义,则编译以下代码#else//如果宏PI未被定义,则编译以下代码#endif```6. #error:当某些条件不满足时,输出错误并停止编译。
例如:```C#error "Something went wrong"```7. #pragma:用于实现一些特殊的功能,这个指令和编译器实现有关。
例如:```C#pragma pack(1) //设置结构体的对齐方式为1字节对齐```。
C语言程序设计 第3版 第9章 编译预处理
#include "test2.c" static int sum(int n) {
int i,s=0; for(i=1;i<=n;i++)
s=s+fact(i); return s; }
static int fact(int n) {
C语言程序设计
第9章 编译预处理
第1讲:编译预处理基本形式
提纲
1.宏定义 2.文件包含 3.条件编译
1.宏定义
不带参数宏定义 带参数宏定义
格式:
#define 标识符 字符串
功能:
指定标识符代替一个较复杂的字符串。
注意说明:
(1)宏名一般习惯用大写字母,例如宏名PI。 (2)宏名用做代替一个字符串,不作语法检查。 (3)宏定义无需在末尾加“;” (4)宏定义的有效范围为#undef命令终止。 (5)在进行宏定义时,可以引用已定义的宏名。
char web[50]; int i=0; gets(web); while(web[i]!='\0') {
#if(R==1) if(web[i]>='A'&&web[i]<='Z') {web[i]=web[i]+32; i++;}
#else if(web[i]>='a'&&web[i]<='z') {web[i]=web[i]-32; i++;}
形式3:
#ifndef 标识符 程序段1
#else 程序段2
C语言910章
C语言教案第九章预处理命令1.C语言中以“#”号开头的行,均为“编译预处理”命令行2.宏作为一个预处理命令,只是简单的文本代换3.在字符串代换过程中,一定要注意不要添加任何字符4.不带参数的宏定义及使用,注意宏中括号的用法5.*当宏定义在一行中写不下,需换行时应在最后一个字符后加“\”6.带参数的宏定义及使用7.注意宏名一般使用大写字母,而参数则不限8.文件包含的两种方法(书上212页)9.*条件编译习题217页:2,3,5第十章指针1.地址和指针的概念,指针型变量的定义2.指针型变量的基类型3.取地址运算符& 和指针运算符*4.通过指针为变量赋值及通过指针找出变量的值的方法5.*为指针变量赋“空”值:p=NULL或p=’\0’ 或p=0(NULL为预定义符,ASCII码值为0)6.函数的形参为指针变量时的数据传递7.通过传送地址值,在被调函数中直接改变主调函数中变量的值8.*函数返回地址值9.指针变量取代数组作函数参数10.一维数组与指针11.一维数组中的几种等价形式:设有定义int a[10], *p=a;数组元素的地址——&a[i], a+i, p+i, &p[i]数组元素——a[i], *(a+i), *(p+i), p[i]12.移动指针,每次移动一个单元13.*指针比较,通常两个或多个指针指向同一目标时比较才有意义14.*数组元素的地址作实参15.*函数的指针形参与函数体中数组的区别16.二维数组与指针17.一个二维数组可看作由多个一维数组构成18.几种等价形式:设有定义int a[5][6], *p=a[0]; 则存在着关于变量和变量的地址间的如下等价形式二维数组元素的地址——&a[i][j], a[i]+j, *(a+i)+j, &a[0][0]+列数*i+j,a[0]+列数*i+j 二维数组元素——a[i][j], *(a[i]+j), *(*(a+i)+j), *(&a[0][0]+列数*i+j),(*(a+i))[j]19.指向指针的指针:int a[5][6], **p=a;20.指针数组:int a[5][6], *p[4]; 定义了具有四个元素的基本整型指针数组21.行指针:int a[5][6], (*p)[6]; 定义了一个指向具有六个元素的一维数组的指向指针的指针型变量22.*二维数组名和指针数组作为实参在函数中的数据传递23.*二级指针和行指针作为实参在函数中的数据传递24.*字符串与指针,直接用字符型指针变量记录字符串的地址25.*指向函数的指针习题278页:2,3,4,9,10,14,15。
C语言对源程序处理的四个步骤:预处理、编译、汇编、链接——预处理篇
C语⾔对源程序处理的四个步骤:预处理、编译、汇编、链接——预处理篇预处理1)预处理的基本概念C语⾔对源程序处理的四个步骤:预处理、编译、汇编、链接。
预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进⾏的处理。
这个过程并不对程序的源代码语法进⾏解析,但它会把源代码分割或处理成为特定的符号为下⼀步的编译做准备⼯作。
2)预编译命令C编译器提供的预处理功能主要有以下四种:1)⽂件包含 #include2)宏定义 #define3)条件编译 #if #endif ..4)⼀些特殊作⽤的预定义宏a、⽂件包含处理1)⽂件包含处理⽂件包含处理”是指⼀个源⽂件可以将另外⼀个⽂件的全部内容包含进来。
C语⾔提供了#include命令⽤来实现“⽂件包含”的操作。
2)#include< > 与 #include ""的区别" "表⽰系统先在file1.c所在的当前⽬录找file1.h,如果找不到,再按系统指定的⽬录检索。
< >表⽰系统直接按系统指定的⽬录检索。
注意:1. #include <>常⽤于包含库函数的头⽂件2. #include " "常⽤于包含⾃定义的头⽂件 (⾃定义的头⽂件常⽤“ ”,因为使⽤< >时需要在系统⽬录检索中加⼊⾃定义头⽂件的绝对地址/相对地址否则⽆法检索到该⾃定义的头⽂件,编译时会报错)3. 理论上#include可以包含任意格式的⽂件(.c .h等) ,但我们⼀般⽤于头⽂件的包含。
b、宏定义1)基本概念在源程序中,允许⼀个标识符(宏名)来表⽰⼀个语⾔符号字符串⽤指定的符号代替指定的信息。
在C语⾔中,“宏”分为:⽆参数的宏和有参数的宏。
2)⽆参数的宏定义#define 宏名 字符串例: #define PI 3.141926在编译预处理时,将程序中在该语句以后出现的所有的PI都⽤3.1415926代替。
C语言的预处理程序与注释
C语言的预处理程序与注释C程序的源代码中可包括各种编译指令,这些指令称为预处理命令。
虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境。
本节将介绍如何应用预处理程序和注释简化程序开发过程,并提高程序的可读性。
1、C语言的预处理程序ANSI标准定义的C语言预处理程序包括下列命令:#define #error #include #if#else #elif #endif #ifdef#ifndef #indef #line #pragma非常明显,所有预处理命令均以符号#开头,下面分别加以介绍。
2、#define命令#define定义了一个标识符及一个串。
在源程序中每次遇到该标识符时,均以定义的串代换它。
ANSI标准将标识符定义为宏名,将替换过程称为宏替换。
命令的一般形式为:#define identifier string注意,该语句没有分号。
在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束。
例如,如希望TURE取值1,FALSE取值0,可说明两个宏#define#define TURE 1#define FALSE 0这使得在源程序中每次遇到TURE或FALSE就用0或1代替。
例如,在屏幕上打印“012”:printf("%d%d%d",FALSE,TRUE,TRUE+1);宏名定义后,即可成为其它宏名定义中的一部分。
例如,下面代码定义了O NE、TWO及THREE的值。
#define ONE 1#define TWO ONE+ONE#define THREE ONE+TWO懂得宏替换仅仅是以串代替标识符这点很重要。
因此,如果希望定义一个标准错误信息,可编写如下代码:#define E_MS "standard error on input\n"printf(E_MS);编译程序遇到标识符E_MS时,就用“standard error on input\n”替换。
C语言中编译预处理命令的解读与应用
C L n u g mpl t n C mma d I tr r t t n a g a e Co i i o a o n n e p eai o
a d Ap l ain o r t ame t n p i t fP er t n c o e
W ANG Xifn . S h n 'i L h ua g UN C e ga , U Ya
a mp r n e t r fte C l n u g . hs a t l o h a g a e c mp lt n c mma d o e t r e p e ra me td f e n i o t tfa u e o a g a e T i r ce n t e C ln u g o i i o a h i ao n ft h e r t t n e n , h e i i cu e i e n lz d i eal w t x mpe fi s f p ca e t r sa d a d t i d e p st n o i a e , o i r n ld , f f ay e n d ti i e a ls o su e o e il au e n eal x o i o f h sp p r C c mp l d a , h t s f e i t e p e rc s o n lsso e C L n u g e c i g a d l an n r ep u . rp o e s ra ay i f h a g a e T a hn n e r i g ae h l f 1 t
可 以使 程 序结 构 优 良 ,更 加 易 于 调试 和 阅 读 。
#en d f e宏名 ( i 参数表) 表达式
例 如 .在源 程 序 中 要使 用 到求 a 、b中两 个 值 中 较 小值 的 函
C语言三种预处理功能
比如#define MAX(a,b) ((a)>(b)?(a):(b))则遇到 MAX(1+2,value)则会把它替换成: ((1+2)>(value)?(1+2):(value))注意事项和无参宏差不多。 但还是应注意
#define FUN(a) "a"
则,输入 FUN(345)会被替换成什么? 其实,如果这么写,无论宏的实参是什么,都不会影响其被替换成"a"的命运。也就是说, ""内的字符不被当成形参,即使它和一模一样。那么,你会问了,我要是想让这里输入 FUN(345)它就替换成"345"该怎么实现呢?请看下面关于#的用法
带参数
除了一般的字符串替换,还要做参数代换
格式: #define 宏名(参数表) 字符串
例如:
#define S(a,b) a*b area=S(3,2);//第一步被换为 area=a*b; ,第二步被换为 area=3*2;
(1)实参如果是表达式容易出问题
#define S(r) r*r area=S(a+b);//第一步换为 area=r*r;,第二步被换为 area=a+b*a+b;
值传递、返回值)。
冷门重点编辑
#define 用法
1、用无参宏定义一个简单的常量
#define LEN 12
这个是最常见的用法,但也会出错。比如下面几个知识点你会吗?可以看下:
(1)#define NAME "zhangyuncong" 程序中有"NAME"则,它会不会被替换呢? (2)#define 0x abcd 可以吗?也就是说,可不可以用不是标识符的字母替换成别的东 西? (3)#define NAME "zhang 这个可以吗? (4)#define NAME "zhangyuncong" 程序中有上面的宏定义,并且,程序里有句: NAMELIST 这样,会不会被替换成"zhangyuncong"LIST 四个题答案都是十分明确的。 第一个,""内的东西不会被宏替换。这一点应该大家都知道; 第二个,宏定义前面的那个必须是合法的用户标识符; 第三个,宏定义也不是说后面东西随便写,不能把字符串的两个""拆开; 第四个:只替换标识符,不替换别的东西。NAMELIST 整体是个标识符,而没有 NAME 标识符,所以不替换。 也就是说,这种情况下记住:#define 第一位置第二位置 (1) 不替换程序中字符串里的东西; (2) 第一位置只能是合法的标识符(可以是关键字); (3) 第二位置如果有字符串,必须把""配对; (4) 只替换与第一位置完全相同的标识符。 还有就是老生常谈的话:记住这是简单的替换而已,不要在中间计算结果,一定要替换出 表达式之后再算。
C语言预处理命令
编译预处理作业
程序2: 程序 : # include <stdio.h> int square(int x) {return(x*x); } main() {int i=1; while(i<=5) printf("%d\n",square(i++)); }
编译预处理
文件包含 格式1: 格式1: 文件标识” #include “[d:][path] 文件标识” 按路径搜索….h文件,若找不到, .h文件 按路径搜索 .h文件,若找不到,则按 系统指定的目录搜索。 系统指定的目录搜索。 格式2: 格式2: <头文件名 头文件名> #include <头文件名> 仅按系统指定的目录搜索。 仅按系统指定的目录搜索。Turbo C 默 认为tc include目录 VC安装路径下 tc\ 目录。 认为tc\include目录。VC安装路径下 的include 目录
编译预处理
对语句a=SQARE(n+1) 对语句a=SQARE(n+1) 1、将替换为a=n+1*n+1; 将替换为a=n+1*n+1; 2、将替换为a=(n+1)*(n+1); 将替换为a=(n+1)*(n+1); 将替换为a=((n+1)*(n+1)); 3、将替换为a=((n+1)*(n+1)); 对语句a=2.7/SQARE(3.0) 对语句a=2.7/SQARE(3.0) 将替换为a=2.7/(3.0)*(3.0); 2、将替换为a=2.7/(3.0)*(3.0); 将替换为a=2.7/((3.0)*(3.0)); 3、将替换为a=2.7/((3.0)*(3.0));
C语言初级学习——预处理命令
9.4 预定义宏
• 预定义宏是C编译器预先定义好的宏,不是 用户定义的,因而不能出现在#define与# undef语句中。 • 如: _ _FILE_ _ _ _DATE_ _ 等一些常见预定义宏标识符。
【例】预定义宏使用举例。
main() { printf("%s\n",__FILE__); printf("%s\n",__DATE__); printf("%s\n",__TIME__); }
结果显示: c:\data\a.c May 22 2001 21:02:54
9.5 运算符#和##
在带参数的宏替换中,若形参中含有#: • #:
“字符串” • 例如: #字符串 #define display(i) printf(#i) ……;display(This is a test);…… 则替换为:printf(“This is a test”);
若有宏定义:#define MOD(x,y) x%y
则执行以下语句后的输出为____
int z, a=15, b=100; z=MOD(b,a); printf(“%d\n”,z++); A 11 C 6 B 10 D 宏定义不合法
若有宏定义如下: #define x 5 #define Y X+1 #define Z Y*X/2 那么执行以下printf语句后,输出结果是____. int a; a=Y; printf(“%d\n”,Z); printf(“%d\n”,--a); A 7 B 12 C 12 D 7 6 6 5 5
#include “文件名称” #include <文件名称>
• 在一些版本的C语言中,还允许“文件名”中 带路径。
C语言预处理命令详解
C语⾔预处理命令详解⼀前⾔预处理(或称预编译)是指在进⾏编译的第⼀遍扫描(词法扫描和语法分析)之前所作的⼯作。
预处理指令指⽰在程序正式编译前就由编译器进⾏的操作,可放在程序中任何位置。
预处理是C语⾔的⼀个重要功能,它由预处理程序负责完成。
当对⼀个源⽂件进⾏编译时,系统将⾃动引⽤预处理程序对源程序中的预处理部分作处理,处理完毕⾃动进⼊对源程序的编译。
C语⾔提供多种预处理功能,主要处理#开始的预编译指令,如宏定义(#define)、⽂件包含(#include)、条件编译(#ifdef)等。
合理使⽤预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。
本⽂参考诸多资料,详细介绍常⽤的⼏种预处理功能。
因成⽂较早,资料来源⼤多已不可考,敬请谅解。
⼆宏定义C语⾔源程序中允许⽤⼀个标识符来表⽰⼀个字符串,称为“宏”。
被定义为宏的标识符称为“宏名”。
在编译预处理时,对程序中所有出现的宏名,都⽤宏定义中的字符串去代换,这称为宏替换或宏展开。
宏定义是由源程序中的宏定义命令完成的。
宏替换是由预处理程序⾃动完成的。
在C语⾔中,宏定义分为有参数和⽆参数两种。
下⾯分别讨论这两种宏的定义和调⽤。
2.1 ⽆参宏定义⽆参宏的宏名后不带参数。
其定义的⼀般形式为:#define 标识符字符串其中,“#”表⽰这是⼀条预处理命令(以#开头的均为预处理命令)。
“define”为宏定义命令。
“标识符”为符号常量,即宏名。
“字符串”可以是常数、表达式、格式串等。
宏定义⽤宏名来表⽰⼀个字符串,在宏展开时⼜以该字符串取代宏名。
这只是⼀种简单的⽂本替换,预处理程序对它不作任何检查。
如有错误,只能在编译已被宏展开后的源程序时发现。
注意理解宏替换中“换”的概念,即在对相关命令或语句的含义和功能作具体分析之前就要进⾏⽂本替换。
【例1】定义常量:1#define MAX_TIME 1000若在程序⾥⾯写if(time < MAX_TIME){.........},则编译器在处理该代码前会将MAX_TIME替换为1000。
c语言的预编译命令
c语言的预编译命令
C语言的预编译命令是#include。
预编译命令是一种特殊的指令,它指示编译器在编译之前执行特定的操作。
在C语言中,#include预编译命令用于包含一个头文件。
它告诉编译器将指定的头文件的内容插入到程序中。
例如,如果你想在程序中使用标准输入输出库中的函数,你可以使用#include <stdio.h>预编译命令来包含该头文件。
这样,编译器就会知道如何处理这些函数,并在编译时将它们包含在最终的程序中。
除了#include之外,C语言还有其他一些预编译命令,如#define、#ifdef、#ifndef等。
这些命令用于在编译时进行条件编译,以根据特定的条件来决定是否包含某些代码块。
C语言预处理命令之条件编译(ifdef,else,endif,if)
C语言预处理命令之条件编译(#ifd ef,#else,#endif,#if)预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。
可见预处理过程先于编译器对源代码进行处理。
在C语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。
要完成这些工作,就需要使用预处理程序。
尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。
预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。
预处理过程还会删除程序中的注释和多余的空白字符。
预处理指令是以#号开头的代码行。
#号必须是该行除了任何空白字符外的第一个字符。
#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。
整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
下面是部分预处理指令:指令用途#空指令,无任何效果#include包含一个源代码文件#define定义宏#undef取消已定义的宏#if如果给定条件为真,则编译下面代码#ifdef如果宏已经定义,则编译下面代码#ifndef如果宏没有定义,则编译下面代码#elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码#endif结束一个#if……#else条件编译块#error停止编译并显示错误信息一、文件包含#include预处理指令的作用是在指令处展开被包含的文件。
包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。
标准C编译器至少支持八重嵌套包含。
预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。
这样就可以在多次包含同一个头文件时,通过给定编译时的条件来达到不同的效果。
例如:#defineAAA#include"t.c"#undefAAA#include"t.c"为了避免那些只能包含一次的头文件被多次包含,可以在头文件中用编译时条件来进行控制。
二级c语言第九章预处理命令
如果在程序中有下面的语句: R1=Radium(100); 那么,在编译预处理时,宏展开的顺序为从左到右进行置换,如果字符串 中包含宏中的形参,则将其用程序语句中相应的实参来替代,而字符串中的 其它字符原样保留。 因此,在处理上述语句时,将用 sqrt(area/PI) 替代 Radium(100),同时将 字符串sqrt(area/PI)中的形参area用实参l00来替代,并把已定义的宏PI的值代 入,经宏展开后,该语句变为“ R1=sqrt(100/3.14159); ”。
内蒙古科技大学 工程训练中心
预处理命令概述
所谓预处理,就是指源程序被正式编译之前所进行的处理工作,这 是C语言和其他高级语言之间的一个重要区别。
所有的预处理指令均以“#”开头,在它前面不能出现空格以外的字 符,而且在行结尾处没有分号。 “预处理命令” 的作用不是实现程序的功能,它们是发布给编译系 统的信息。它们告诉编译系统,在对源程序进行编译之前应该做些什么, 所以称这类语句为编译预处理命令。 C语言在执行一个C程序时,如果程序中有预处理命令,则首先进行 编译预处理(即根据预处理命令对源程序进行预先处理),然后再将经过 预处理的源程序编译成目标文件,而后进行目标文件的连接,当这些工 作都顺利通过后,才最终执行目标代码。这种执行过程大大提高了编程 效率。
PI 的有效范围
因为#undef 的作用是终止宏定义,因此PI的作用域从它定义开始到 #undef结束。在这以后,如果程序中出现 PI,则它不代表3.14159 。使 用#undef可以灵活控制宏定义的作用范围。
2019年1月8日5时29分 工程训练中心 徐国海
(二)带参数宏定义 (了解) 定义的一般格式为: #define 宏名(形式参数列表) 字符串
C语言9
第 九 章 编 译 预 处 理
7-1
宏定义 不带参数的宏定义 带参数的宏定义
7-1-1 7-1-2
7-2
7-3
文件包含
条件编译
9-1
宏定义
例9-1 请看下面的程序: #define PI 3.14159 main() {float r,l,s; scanf("%f",&r); l=2*PI*r; s=PI*r*r; printf("l=%7.2f,s=%7.2f\n",l,s); } 程序的第一行内容:#define PI 3.14159 就是一个宏定义,PI 称为宏名,其作用是用标识符PI代表3.14159这样一串字符。在此之后 的程序中就可以用标识符PI代替3.14159,称为宏引用。 预处理时,程序中的PI 将被所定义的串3.14159替换,称为宏展开 或宏替换,如程序中的语句:l=2*PI*r;和s=PI*r*r;中的宏展开后分别 为:l=2*3.14159*r;和s=3.14159*r*r;。 有两种形式的宏 :不带参数的宏和带参数的宏。
9-2
文件包含(1)
一个C 程序由若干个源程序组成,而一个源文件还可以将另一个源 文件的全部内容包含进来,即将指定源文件的内容包含在当前文件中。 例如有两个源文件file1.c和file2.c,文件的内容分别如下: file1.c的内容: int max(int x,int y) {int z; if(x>y) z=x; else z=y; return z; } file2.c的内容: #include "file1.c" main() {int a,b,c; scan("%d,%d",&a,&b); c=max(a,b); printf("c=%d\n",c); }
C语言三种预处理
当满足某条件时对一组语句进行编译,而条件不满足时则编译另一组语句。 形式:
#ifndef 标识符 程序段 1
#else 程序段 2
#endif 若标识符未被定义则编译程序段 1,否则编译程序段 2。 优点: 采用条件编译,可以减少被编译的语句,从而减少目标的长度。当条件编译 段比较多时,目标程序长度可以大大减少。
1.2 带参数的宏定义 格式:
#define 宏名(参数表) 字符串 举例:
#define S(a,b) ((a)*(b)) 说明:
①宏名和参数间不能有空格! ②宏替换只做替换,不做计算和表达式求解! ③宏展开不占程序运行时间只占编译时间! 掌握宏概念的关键在“替换”!
2.文件包含 由来:
文件包含处理在程序开发中会给模块化程序设计带来很大的好处,通过文件 包含的方法把程序中的各个功能模含处理是指在一个源文件中,通过文件包含命令将另一个源文件的内
容全部包含在此文件中。在源文件编译时,连同被包含进来的文件一同编译,生 成目标目标文件。 形式:
①#include "文件名"; 或
②#include <文件名>; 两种形式区别:
①系统首先在用户当前目录中寻找要包含的文件,若未找到才到包含目录中 去查找;
C 语言提供 3 种预处理功能:①宏定义②文件包含③条件编译。
0.预处理指令 预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第
一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。 整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某 些转换。
②系统在包含文件目录中去查找(包含目录由用户在设置环境时设置)而不 在源文件目录去查找。若文件不在当前目录中,双撇号内可给出文件路径。 说明:
C语言的预处理命令有哪些?
问:关于C语言中的预处理命令?答:我们可以在C源程序中插入传给编译程序的各种指令,这些指令被称为预处理器指令(等价于汇编语言中的伪指令),它们扩充了程序设计的环境。
现把常用的预处理命令总结如下:1. 预处理程序按照ANSI标准的定义,预处理程序应该处理以下12条指令:#if、#ifdef、#ifndef、#else、#elif、#endif、#define、#undef、#line、#error、#pragma、#include。
显然,所有的12个预处理指令都以符号#开始,,每条预处理指令必须独占一行。
2. #define#define指令定义一个标识符和一个串(也就是字符集),在源程序中发现该标识符时,都用该串替换之(原样替换,不要附加任何人为理解上的符号)。
这种标识符称为宏名字,相应的替换称为宏代换。
一般形式如下:#define macro-name char-sequence这种语句不用分号结尾。
宏名字和串之间可以有多个空格符,但串开始后只能以新行终止。
在C语言里宏定义只用来做的宏名替换,而不做语法检查的,因而它不是C语句,所以宏定义的语句结尾不需要加分号。
宏也在C里也叫预处理命令,因为宏是在程序编译前先进行字符替换的,所以叫预处理.例如:我们使用LEFT代表1,用RIGHT代表0,我们使用两个#define指令:#define LEFT 1#define RIGHT 0每当在源程序中遇到LEFT或RIGHT时,编译程序都用1或0替换。
定义一个宏名字之后,可以在其他宏定义中使用,例如:#define ONE 1#define TWO ONE+ONE#define THREE ONE+TWO宏代换就是用相关的串替代标识符。
因此,如果希望定义一条标准错误信息时,可以如下定义:#define ERROR_MS “Standard error on input \n”如果一个串长于一行,可在行尾用反斜线”\”续行,如下:#define LONG_STRING “This is a very very long \s tring that is used as an example”3. #error#error指令强制编译程序停止编译,它主要用于程序调试(放在错误的分支中,一旦进入错误的分支就显示该信息)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
对宏进行预编译,展开后的main函数如下: 对宏进行预编译,展开后的main函数如下: main函数如下
void main() main() { float r,l,s,v; scanf("%f",&r); l=2*3.1415926*r; s=3.1515926*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\ printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v); }
运行情况如下: 运行情况如下:
L=18.849556 S=28.274333
经过宏展开后,printf函数中的输出项L被展开为: 2*3.1415926*3.0 S展开为 3.1415926*3.0*3.0 printf函数调用语句展开为:
printf("L=%F\NS=%f\n", 2*3.1415926*3.0,3.1415926*3.0*3.0);
说明: 说明:
(8) 对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行置 换. (9) 宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同, 只作字符替换,不分配内存空间.
9.1.2 带参数的宏定义
作用:不是进行简单的字符串替换,还要进行参数替换. 作用:不是进行简单的字符串替换,还要进行参数替换.
例9.4 通过宏展开得到若干个结果
#include <stdio.h> #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 void 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\ printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v); }
带参数的宏定义一般形式为: 带参数的宏定义一般形式为:
#define 宏名(参数表) 字符串 宏名(参数表) 字符串中包含在括弧中所指定的参数
例:
#define S(a,b) a*b : area=S(3,2);
程序中用3和2分别代替宏定义中的形式
参数a和b,用3*2代替S(3,2) 参数a和b,用3*2代替S(3,2) .因此赋 值语句展开为: area=3*2
其一般形式为: 其一般形式为: #include "文件名" "文件名 文件名" 或 #include <文件名> <文件名 文件名>
将例9 时格式宏做成头文件, 例9.6 将例9.5时格式宏做成头文件,把它 包含在用户程序中. 包含在用户程序中. (2)主文件 主文件file1.c (2)主文件file1.c
赋值语句"area=S(a); " 经宏展开后为: area=3.1415926*a area=3.1415926*a*a;
说明: 说明:
(1)对带参数的宏展开只是将语句中的宏名后面括号内的实参字符串代替# (1)对带参数的宏展开只是将语句中的宏名后面括号内的实参字符串代替# define 命令行中的形参. (2) 在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后 的字符都作为替代字符串的一部分.
第九章
本章要点
预处理的概念 C语言处理系统的预处理功能 预处理命令的使用
主要内容
9.1 宏定义 9.2"文件包含" 9.2"文件包含"处理 9.3 条件编译
基本概念
ANSI C标准规定可以在C源程序中加入一些"预处理命令" ,以改进 C标准规定可以在C源程序中加入一些"预处理命令"
程序设计环境,提高编程效率. 这些预处理命令是由ANSI C统一规定的,但是它不是C 这些预处理命令是由ANSI C统一规定的,但是它不是C语言本身的组成 部分,不能直接对它们进行编译(因为编译程序不能识别它们).必须 在对程序进行通常的编译之前,先对程序中这些特殊的命令进行" 在对程序进行通常的编译之前,先对程序中这些特殊的命令进行"预处 理" 经过预处理后程序可由编译程序对预处理后的源程序进行通常的编译处 理,得到可供执行的目标代码.
基本概念
C语言与其他高级语言的一个重要区别是可以使用预处理命令和具有预
处理的功能. C提供的预处理功能主要有以下三种: 1.宏定义 2.文件包含 3.条件编译 这些功能分别用宏定义命令,文件包含命令,条件编译命令来实现. 为了与一般C语句相区别,这些命令以符号" 为了与一般C语句相区别,这些命令以符号"#"开头.例如: #define #include
运行时输出结果:
1 12 123 1234 CHINA
§9.2 "文件包含"处理 文件包含"
所谓"文件包含"处理是指一个源文件可以将另外一个源文件的全部内容包 所谓"文件包含"
含进来.C语言提供了#include命令用来实现"文件包含" 含进来.C语言提供了#include命令用来实现"文件包含"的操作.
对带参的宏定义是这样展开置换的:
对带实参的宏(如S(3,2),则按# 对带实参的宏(如S ),则按#
define命令行中指定的字符串从左到右 define命令行中指定的字符串从左到右 进行置换.若串中包含宏中的形参(如a 进行置换.若串中包含宏中的形参(如a, b),则将程序中相应的实参(可以是常 量,变量或表达式)代替形参.如果宏 定义中的字符串中的字符不是参数字符 (如a*b中的* (如a*b中的*号),则保留.这样就 形成了置换的字符串.
如果善于利用宏定义,可以实现程序的简化,如事先将程序中的 "输出格式"定义好,以减少在输出语句中每次都要写出具体的 输出格式" 输出格式的麻烦.
例9.dio.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" void main() { int a,b,c,d; 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); }
说明: 说明:
(4) 宏定义不是C语句,不必在行末加分号.如果加了分号则会连分号一起进行 置换. (5) #define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到 define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到 本源文件结束.通常,#define命令写在文件开头,函数之前,作为文件一 本源文件结束.通常,#define命令写在文件开头,函数之前,作为文件一 部分,在此文件范围内有效. (6) 可以用#undef命令终止宏定义的作用域. 可以用#undef def命令终止宏定义的作用域. 例如:
例9.3 使用带参的宏
运行情况如下: 运行情况如下:
#include <stdio.h> r=3.600000 #define PI 3.1415926 area=40.715038 #define S(r) PI*r*r void main() {float a,area; a=3.6; area=S(a); printf("r=%f\narea=%f\ printf("r=%f\narea=%f\n",a,area); }
#define G 9.8 void main() { … } #undef G f1() { … }
_______ ↑ G的有效范围 -----↓ -----↓----
在f1函数中,G不再代表 f1函数中,G不再代表 函数中,G 9.8. 9.8.这样可以灵活控制宏 定义的作用范围. 定义的作用范围.
§9.1 宏定义
9.1.1 不带参数的宏定义 宏定义一般形式为: 宏定义一般形式为: #define 标识符 字符串
例如:# define PI 3.1415926 例如:#
宏定义的作用是在本程序文件中用指定的标识符PI来代替"3.1415926"这个字符 宏定义的作用是在本程序文件中用指定的标识符PI来代替"3.1415926"
例9.1 使用不带参数的宏定义
#include <stdio.h> #define PI 3.1415926 void main() {float l,s,r,v; printf("input radius:"); scanf("%f",&r); l=2.0*PI*r; l=2.0*PI*r; s=PI*r*r; s=PI*r*r; v=4.0/3*PI*r*r*r; v=4.0/3*PI*r*r*r; printf("l=%10.4f\ns=%10.4f\nv=%10.4f\ printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v); }
带参数的宏和函数的区别: 带参数的宏和函数的区别: