樊媛媛《c语言程序设计》09-编译预处理

合集下载

C语言编译预处理PPT课件

C语言编译预处理PPT课件

知识点精讲
知识点2 不带参数的宏定义
知识点分析 用一个指定的标识符(即名字)来代表一个字符串,其一般形式如下: #define 标识符 字符串 例如: #define PI 3.1415926 1.宏定义的作用是在本程序文件中用指定的标识符PI来代替3.141 592 6这个字符串。在编译 预处理时,将程序中在该命令后出现的所有PI都用3.141 592 6代替。这种方法使用户能够以一个 简单的名字代替一个长的字符串。 2.这个标识符(名字)称为“宏名”。 3.在预处理时,将宏名替换成字符串的过程称为“宏展开”。“#define”是宏定义命令。 例如: #include "stdio.h" #define PI 3.1415926 /*定义了一个不带参数的宏*/
知识点精讲
int sum=ADD ( m+n)*k; printf("sum=%d", sum); } 2.下列程序的运行结果是____s_u_m_=_1_2_______ #define ADD(x)(x)+(x) void main( ) { int m=1,n=2,k=3; int sum=ADD(m+n)*k; printf("sum=%d", sum); } 3.下列程序的运行结果是______2_8________ #include <stdio.h> #define f(x) x*x main( )
void main( )
{
printf("L=%f\nS=%f\n",L,S);
getch( );
}
知识点精讲
知识点3 带参数的宏定义
真题回顾 (2021年真题)计算圆的面积s(公式为s=3.14r2)。请补全下列代码。 #include<stdio.h>

c语言教程9

c语言教程9
int factorial(int num) {
if(num==0) return 1;
else {
#ifddeeffiDneEdB(UDGEBUG) static int i; printf(“call times:%d,num=%d\n”,++i,num);
#endif return(factorial(num-1)*num); } }
b=(a)*(a)*(a)
a=? b=?
b=CUBE(a++)
b=(a++)*(a++)*(a++)
int cube(int x) {
return x*x*x; }
void main () {
… int b=0,a=3; bb==ccuubbee((aa+);+); }
2. 文件包含 文件包含格式:
#else 语句或预处理命令表列2
#endif
格式3:
#ifndef 标识符 语句或预处理命令表列
#endif
或 #ifndef 标识符 语句或预处理命令表列1 #else 语句或预处理命令表列2 #endif
#include<stdio.h> /#/d#edfienfeinDeEDBEUBGUG
END
直接在C系统的include目 录中查找该文件
#include<文件名> 或
#include ”文件名” 先从源程序所在的当前目 录中查找该文件;如果找 不到的话,再到include 中 查找
3. 条件编译 条件编译是源文件内系统级的选择结构,用于控制编译器
有选择地对源程序中的某个部分进行编译或不进行编译。

谭浩强--C语言程序设计09

谭浩强--C语言程序设计09

9.1 编译预处理(续)
9.1.1 不带参数的宏定义p187
命令的一般格式:
#define 宏名 字符串
4
宏定义的功能: 在进行编译前,用字符串原样替换程序中的 宏名。 这个替换过程称为“宏替换”或“宏展开”, 字符串也称为替换文本。
9.1 编译预处理(续)
例如: #define PI 3.14
9.1 编译预处理(续)
10
【例9.3】分析下面程序运行后的输出结果。 #define MA(x) x*(x-1) 特别注意: main( ) 由于替换文 { int a=1,b=2; 本中的x没 有用括号括 printf("%d\n", MA(1+a+b)); 起,因此, } 1+a+b也不 程序输出结果:8 能用括号括 分两次替换: 起。 ①MA(1+a+b) 用x*(x-1) 替换。 ②用1+a+b替换x。 printf语句被展开为: 例903 printf("%d\n", 1+a+b*(1+a+b-1));
9.1编译预处理(续)
2.功能
在预处理时,将include命令后指定文件的内 容替换该命令行。 例如:调用sin(x) 函数时,要在程序的开头使用 如下命令: #include <math.h> 在预处理时,用math.h文件内容替换 #include <math.h>命令行。
13
9.2 多文件程序的调试方法p184
例9021-2
9.1 编译预处理(续)
9.1.2 带参数的宏定义
命令的一般形式 #define 宏名(形参表) 字符串

第8章 编译预处理

第8章 编译预处理

11
第8章 编译预处理
8.2 文件包含@include
12
所谓“文件包含”处理是指一个源文件可以将另外一个源 文件的全部内容包含进来,即将另外的文件包含到本文件之 中。C语言提供了#include命令用来实现“文件包含”的 操作。一般形式为: #include “文件名” 或 #include <文件名> 在程序设计中,文件包含是很有用的。有些公用的符号常 量或宏定义等可单独组成一个文件,在其他文件的开头用 包含命令包含该文件即可使用。这样,可避免在每个文件 开头都去书写那些公用量,这样可以节省时间、减少出错。 对于C系统提供的标准库函数,也可以通过文件包含使之 包含到当前的程序里,从而实现库函数的调用。例如在前 面章节中已经用到的文件包含处理:
宏定义#define
2. 带参有宏定义
在以上例子中,要注意如下问题: (1)带参宏定义中,宏名和形参表之间不能随 便加入空格;否则将空格以后的字符都作为替代 字符串的一部分。 例如把上例中的宏定义: #define MAX(x,y)(x>y)?x:y 写成: #define MAX (x,y)(x>y)?x:y 将被认为是无参宏定义,宏名定义MAX代表字符 串(x,y)(x>y)?x:y 。 在上例中的宏定义语句中插入空格后,编译将失 败。
13
第8章 编译预处理
8.2 文件包含@include (4) 如果文件file1包含文件file2,而在文件file2中又要包含文件file3的 内容,则可在文件file1用两个#include命令分别包含文件file2和文件 file3,而且文件file3要出现在文件file2之前,即在文件file1.c中定义: #include <file3.h> #include <file2.h> 这样file1和file2都可以用file3的内容。 (5) 在一个被包含文件中又可以包含另一个被包含文件,即文件包含 是可以嵌套的。 (6) 被包含文件(如file2.h)与其所在文件(如file1.c),经编译预处理后 已成为同一文件,因此,如果file2.h中有全局静态变量,它在文件 file1.c中有效,不必用extern声明。

《C语言程序设计教程(第4版)》第6章编译预处理

《C语言程序设计教程(第4版)》第6章编译预处理
令行后出现的宏名用宏体代替。
实例
#define PI 3.1415926
main() {float a,s,r;
宏调用
printf("Input radius r:");
scanf("%f", &r);
宏替换后:
a=2*PI*r;
a=2*3.1415926*r;
s=PI*r*r;
s=3.1415926*r*r;
宏名在源程序中若用引号引起来,则预处理程序不
对其作宏代换。如:#define no 220
main()
不替换Biblioteka { printf(“no”); }
说明
宏定义可以嵌套:
在宏体中可以使用已经定义的宏名。在宏展
开时由预处理程序层层代换。
以下程序中的for循环执行的次数是( )。 思考
#define N 2
scanf("%d",&y);
s=3*My*y+3*y +4*My*y+3*y
printf("s=%d\n",s);
}
(y*y+3*y) (y*y+3*y)
+5*My;*y+3*y (y*y+3*y)
带参宏定义
一般形式: #define 宏名(形参表) 宏体
宏调用:宏名(实参表)
宏替换:编译预处理时用宏体代换带参宏,同时 用实参代换形参
如:有参宏 # define AS(x,y,z) x+y+z
无参宏定义
一般形式: #define 宏名 宏体 define:宏定义命令 宏名:由标识符定义 宏体:为一字符串(常量、表达式、格式串等) define、宏名、宏体之间用空格隔开

C语言程序设计 第3版 第9章 编译预处理

C语言程序设计 第3版 第9章 编译预处理
int s; s=sum(5); printf("s%d\n",s); }
#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语言程序设计 CPD_10 更多课件请进我文库

C语言程序设计 CPD_10 更多课件请进我文库
3
计算机程序设计基础
北京工商大学 何渝
从C/C++程序看编译预处理
原 来 现 编 在 辑
编 辑
预 编 译 编 译

连 接 连 运

接 行
4
运 行
计算机程序设计基础
北京工商大学 何渝
10.2 宏替换(宏定义)
程序中可以用#define命令定义字符串宏
替换: #define 宏名 宏体 使用宏替换的好处: 1. 提高程序的可读性。如一些常数。 2. 易修改性。如需要多处修改相同内容
何 渝 北京工商大学 计算机与信息工程学院
计算机程序设计基础
北京工商大学 何渝
本章主要内容
• 编译预处理 • 多文件编程
2
计算机程序设计基础
北京工商大学 何渝
§10.1 编译预处理
编译预处理是C/C++特有的功能,它是在编译 前对源程序进行的一些预加工处理,由编译系统中 的预处理程序按源程序的预处理命令进行处理。 C/C++语言的预处理均以#号打头,末尾不加 分号,以区别于函数和变量的声明。它们可出现在 程序中的任何位置,其作用域是自出现点到所在源 程序的末尾。 编译预处理是C/C++的一个重要特性。它能改 善程序设计的环境,有助于编写易移植、易维护的 程序,也是模块化程序设计的一个工具。包括: 1. 宏替换 2. 文件包含 3. 条件编译
6
计算机程序设计基础
北京工商大学 何渝
注:
• 宏替换中的宏体不仅可以是字符串常数,也可是
表达式或语句组成的字符串,还可是多个语句,如: #define PI 3.1416 #define RADIUS 2.0 #define CIRCUM return(2.0*PI*RADIUM) • C中定义常量,在C++中用const语句代替,如: const PI=3.14;

c语言编译过程详解

c语言编译过程详解

C语言编译过程通常分为预处理、编译、汇编和链接四个步骤。

以下是C语言编译过程的详细解释:
1. 预处理:在编译之前,预处理器会对源代码进行预处理。

预处理包括以下步骤:
-删除源代码中的注释
-展开宏定义
-处理文件中的预定义符号
2. 编译:编译器将预处理后的代码转换成中间代码(即汇编语言)。

编译器会对源代码进行词法分析、语法分析和优化,生成目标代码(即汇编语言)。

3. 汇编:汇编器将汇编代码转换成机器指令。

汇编器将汇编指令转换成机器指令,并将它们组合成可执行的程序。

4. 链接:链接器将多个目标文件组合成一个可执行文件或共享库文件。

链接器会解决符号引用问题,并将它们链接到相应的代码段和数据段。

在C语言编译过程中,编译器和链接器通常使用标准库和用户定义的库。

标准库提供了一些常用的函数和数据类型,如printf()和malloc()。

用户定义的库可以包含自定义的函数和数据类型,以便更好地满足应用程序的需求。

总之,C语言编译过程是一个复杂的过程,需要多个步骤和工具的协同工作。

正确的编译过程可以确保生成的可执行程序具有良好的性能和可靠性。

C语言程序设计教程ppt课件完整版pptx

C语言程序设计教程ppt课件完整版pptx
C语言的应用领域
计算机系统基本概念
计算机系统的组成 操作系统的基本概念 计算机中的数与编码
编程环境与工具安装配置
01
常见的C语言编程环境
02
安装与配置C语言编译器
使用集成开发环境(IDE)进行C语言编程
03
第一个C程序:Hello, World!
01
C程序的基本结 构
02
编写Hello, World!程序
应用场景
适用于需要根据特定条件提前终 止循环或跳过某些循环操作的情 况。
04 函数与模块化设计
函数定义和调用
01
函数定义
包括函数名、参数列表、返回值 类型和函数体等部分,用于描述 函数的功能和实现细节。
函数调用
02
03
函数声明
通过函数名和参数列表来调用函 数,实现相应功能并获取返回值 。
在使用函数之前,需要对函数进 行声明,以便编译器识别函数的 存在和调用方式。
THANKS FOR WATCHING
感谢您的观看
指针运算符
包括取地址运算符&和取值运算符*,分别 用于获取变量的内存地址和通过指针访问内 存中的数据。
动态内存分配函数(malloc, free)使用方法
malloc函数
用于在堆区动态分配指定大小的内存空间,并返回 分配内存的起始地址。
free函数
用于释放之前通过malloc函数分配的内存空间,防 止内存泄漏。
动态规划思想
动态规划是一种在数学、计算机科学和经济学中 使用的,通过把原问题分解为相对简单的子问题 的方式来求解复杂问题的方法。动态规划常用于 优化重叠子问题的计算。
回溯与分支限界法
回溯法是一种通过探索所有可能的候选解来找出 所有解的算法,而分支限界法是一种通过剪枝来 减少搜索空间的优化算法。回溯与分支限界法常 用于解决组合优化问题。

c语言的编译流程

c语言的编译流程

c语言的编译流程C语言是一种高级编程语言,被广泛用于系统软件、游戏开发、嵌入式系统等领域。

在使用C语言进行编程时,需要将代码转换为可执行文件,这个过程称为编译。

本文将介绍C语言的编译流程,以及编译过程的主要步骤。

1. 预处理(Preprocessing):编译过程的第一步是预处理,它由预处理器(Preprocessor)执行。

预处理器主要完成以下任务:- 处理以“#”开头的预处理指令,例如#include、#define、#ifdef 等。

- 将所有的#include指令替换为相应的头文件的内容。

-进行宏替换,将程序中的宏定义展开。

- 词法分析(Lexical Analysis):将代码分解为一个个的单词,称为记号(Token)。

- 语法分析(Syntax Analysis):根据语法规则组织单词,并创建语法树(Syntax Tree)。

- 语义分析(Semantic Analysis):对语法树进行分析,检查语义错误,并生成中间代码。

3. 汇编(Assembly):编译器生成的中间代码是与特定平台无关的,需要通过汇编器(Assembler)将其转换为可执行文件。

汇编器主要完成以下任务:-将汇编代码转换为机器码指令。

-将符号名称解析为地址,生成可重定位代码。

4. 链接(Linking):在C语言编程中,通常会使用多个源文件,这些文件中的函数和变量可能相互引用。

链接器(Linker)的作用是将这些文件中的符号引用和定义进行匹配,生成最终的可执行文件。

链接器主要完成以下任务:- 符号解析(Symbol Resolution):将符号引用与符号定义进行匹配。

- 地址重定位(Address Relocation):将代码中的相对地址转换为绝对地址。

- 符号合并(Symbol Merging):将多个源文件中同名的符号进行合并,以解决重复定义的问题。

-生成可执行文件,包括代码段、数据段等。

5. 加载(Loading):加载器(Loader)是操作系统提供的一部分,它将可执行文件加载到内存中,并执行程序。

C语言程序设计教程 第6章

C语言程序设计教程 第6章
2017/8/21 11
模块设计的原则
模块独立
规模适当
层次分明
2017/8/21
功能专一
12
独立性原则表现在模块完成独立的功能 , 和其它模块间的关系简单 , 各模块可以单独调 试。修改某一模块 , 不会造成整个程序的混乱。
每个模块有特定功能
每个模块完成一个相对独立的特定子功能。在对任务逐步 分解时,要注意对问题的综合。例如, 一些模块的相似的 子任务,可以把它们综合起来考虑,找出它们的共性,把它 们做成一个完成特定任务的单独模块。
返回值
另外请注意这样的判断,如写成‘ 最好只使用局部变量,这样将方便调试。 如果不需返回则可 调用函数时输入参数的格式要与之相同 return 0; A‟<capital<„Z‟是不行 注意不要与已有库函数重名 的 2017/8/21
24
“函数”的主要知识点
函数的定义 函数的参数和返回值 函数的调用 嵌套和递归 变量的作用域
2017/8/21
18
例6.2 设计算法:找出a,b两数中的较大者,并输出
分析: 这个问题分三个步骤: • 输入两个数; • 找出其中的大数; • 输出大数。
2017/8/21
19
开始
输入a,b
0 a<b 非0 交换a,b 输出a
结束
2017/8/21
图6.3 找出a,b两数中的较大者算法流程图
2017/8/21
34
函数返回值
函数返回值通过return语句获得 函数返回值的类型就是函数的类型 return y; 将变量y的值返回给调用者 return y+3; 将表达式的值返回给调用者
2017/8/21 35
return 的数据类型与函数的类型矛盾时,自动 将数据转换成函数的类型

C语言的编译预处理

C语言的编译预处理

C语言的编译预处理发布:2009-11-11 13:56 | 作者:hnrain | 来源:本站| 查看:44次| 字号: 小中大在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译器处理之前, 预处理器首先对源程序中的"宏(macro)"进行处理.C初学者可能对预处理器没什么概念, 这是情有可原的: 一般的C编译器都将预处理, 汇编, 编译, 连接过程集成到一起了. 编译预处理往往在后台运行. 在有的C编译器中, 这些过程统统由一个单独的程序来完成, 编译的不同阶段实现这些不同的功能. 可以指定相应的命令选项来执行这些功能. 有的C编译器使用分别的程序来完成这些步骤. 可单独调用这些程序来完成. 在gcc中, 进行编译预处理的程序被称为CPP, 它的可执行文件名为cpp.编译预处理命令的语法与C语言的语法是完全独立的. 比如: 你可以将一个宏扩展为与C语法格格不入的内容, 但该内容与后面的语句结合在一个若能生成合法的C语句, 也是可以正确编译的.(一) 预处理命令简介--------------------------------------------------------------------------------预处理命令由#(hash字符)开头, 它独占一行, #之前只能是空白符. 以#开头的语句就是预处理命令, 不以#开头的语句为C中的代码行. 常用的预处理命令如下:#define 定义一个预处理宏#undef 取消宏的定义#include 包含文件命令#include_next 与#include相似, 但它有着特殊的用途#if 编译预处理中的条件命令, 相当于C语法中的if语句#ifdef 判断某个宏是否被定义, 若已定义, 执行随后的语句#ifndef 与#ifdef相反, 判断某个宏是否未被定义#elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if#else 与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else#endif #if, #ifdef, #ifndef这些条件命令的结束标志.defined 与#if, #elif配合使用, 判断某个宏是否被定义#line 标志该语句所在的行号# 将宏参数替代为以参数值为内容的字符窜常量## 将两个相邻的标记(token)连接为一个单独的标记#pragma 说明编译器信息#warning 显示编译警告信息#error 显示编译错误信息(二) 预处理的文法--------------------------------------------------------------------------------预处理并不分析整个源代码文件, 它只是将源代码分割成一些标记(token), 识别语句中哪些是C语句, 哪些是预处理语句. 预处理器能够识别C标记, 文件名, 空白符, 文件结尾标志.预处理语句格式: #command name(...) token(s)1, command预处理命令的名称, 它之前以#开头, #之后紧随预处理命令, 标准C允许#两边可以有空白符, 但比较老的编译器可能不允许这样. 若某行中只包含#(以及空白符), 那么在标准C中该行被理解为空白. 整个预处理语句之后只能有空白符或者注释, 不能有其它内容.2, name代表宏名称, 它可带参数. 参数可以是可变参数列表(C99).3, 语句中可以利用"\"来换行.e.g.# define ONE 1 /* ONE == 1 */等价于: #define ONE1#define err(flag, msg) if(flag) \printf(msg)等价于: #define err(flag, msg) if(flag) printf(msg)(三) 预处理命令详述--------------------------------------------------------------------------------1, #define#define命令定义一个宏:#define MACRO_NAME(args) tokens(opt)之后出现的MACRO_NAME将被替代为所定义的标记(tokens). 宏可带参数, 而后面的标记也是可选的. 对象宏不带参数的宏被称为"对象宏(objectlike macro)"#define经常用来定义常量, 此时的宏名称一般为大写的字符串. 这样利于修改这些常量.e.g.#define MAX 100int a[MAX];#ifndef __FILE_H__#define __FILE_H__#include "file.h"#endif#define __FILE_H__ 中的宏就不带任何参数, 也不扩展为任何标记. 这经常用于包含头文件.要调用该宏, 只需在代码中指定宏名称, 该宏将被替代为它被定义的内容.函数宏带参数的宏也被称为"函数宏". 利用宏可以提高代码的运行效率: 子程序的调用需要压栈出栈, 这一过程如果过于频繁会耗费掉大量的CPU运算资源. 所以一些代码量小但运行频繁的代码如果采用带参数宏来实现会提高代码的运行效率.函数宏的参数是固定的情况函数宏的定义采用这样的方式: #define name( args ) tokens其中的args和tokens都是可选的. 它和对象宏定义上的区别在于宏名称之后不带括号.注意, name之后的左括号(必须紧跟nam e, 之间不能有空格, 否则这就定义了一个对象宏, 它将被替换为以(开始的字符串. 但在调用函数宏时, name与(之间可以有空格.e.g.#define mul(x,y) ((x)*(y))注意, 函数宏之后的参数要用括号括起来, 看看这个例子:e.g.#define mul(x,y) x*y"mul(1, 2+2);" 将被扩展为: 1*2 + 2同样, 整个标记串也应该用括号引用起来:e.g.#define mul(x,y) (x)*(y)sizeof mul(1,2.0) 将被扩展为sizeof 1 * 2.0调用函数宏时候, 传递给它的参数可以是函数的返回值, 也可以是任何有意义的语句:e.g.mul (f(a,b), g(c,d));e.g.#define insert(stmt) stmtinsert ( a="1"; b="2";) 相当于在代码中加入a="1"; b="2" .insert ( a="1", b="2";) 就有问题了: 预处理器会提示出错: 函数宏的参数个数不匹配. 预处理器把","视为参数间的分隔符.insert ((a=1, b="2";)) 可解决上述问题.在定义和调用函数宏时候, 要注意一些问题:1, 我们经常用{}来引用函数宏被定义的内容, 这就要注意调用这个函数宏时的";"问题.example_3.7:#define swap(x,y) { unsigned long _temp=x; x="y"; y=_tmp}如果这样调用它: "swap(1,2);" 将被扩展为: { unsigned long _temp=1; 1=2; 2=_tmp};明显后面的;是多余的, 我们应该这样调用: swap(1,2)虽然这样的调用是正确的, 但它和C语法相悖, 可采用下面的方法来处理被{}括起来的内容:#define swap(x,y) \do { unsigned long _temp=x; x="y"; y=_tmp} while (0)swap(1,2); 将被替换为:do { unsigned long _temp=1; 1=2; 2=_tmp} while (0);在Linux内核源代码中对这种do-while(0)语句有这广泛的应用.2, 有的函数宏是无法用do-while(0)来实现的, 所以在调用时不能带上";", 最好在调用后添加注释说明. eg_3.8:#define incr(v, low, high) \for ((v) = (low),; (v) <= (high); (v)++)只能以这样的形式被调用: incr(a, 1, 10) /* increase a form 1 to 10 */函数宏中的参数包括可变参数列表的情况C99标准中新增了可变参数列表的内容. 不光是函数, 函数宏中也可以使用可变参数列表.#define name(args, ...) tokens#define name(...) tokens"..."代表可变参数列表, 如果它不是仅有的参数, 那么它只能出现在参数列表的最后. 调用这样的函数宏时, 传递给它的参数个数要不少于参数列表中参数的个数(多余的参数被丢弃).通过__VA_ARGS__来替换函数宏中的可变参数列表. 注意__VA_ARGS__只能用于函数宏中参数中包含有"..."的情况.e.g.#ifdef DEBUG#define my_printf(...) fprintf(stderr, __VA_ARGS__)#else#define my_printf(...) printf(__VA_ARGS__)#endiftokens中的__VA_ARGS__被替换为函数宏定义中的"..."可变参数列表.注意在使用#define时候的一些常见错误:#define MAX = 100#define MAX 100;=, ; 的使用要值得注意. 再就是调用函数宏是要注意, 不要多给出";".注意: 函数宏对参数类型是不敏感的, 你不必考虑将何种数据类型传递给宏. 那么, 如何构建对参数类型敏感的宏呢? 参考本章的第九部分, 关于"##"的介绍.关于定义宏的另外一些问题(1) 宏可以被多次定义, 前提是这些定义必须是相同的. 这里的"相同"要求先后定义中空白符出现的位置相同, 但具体的空白符类型或数量可不同, 比如原先的空格可替换为多个其他类型的空白符: 可为tab, 注释...e.g.#define NULL 0#define NULL/* null pointer */ 0上面的重定义是相同的, 但下面的重定义不同:#define fun(x) x+1#define fun(x) x + 1 或: #define fun(y) y+1如果多次定义时, 再次定义的宏内容是不同的, gcc会给出"NAME redefined"警告信息.应该避免重新定义函数宏, 不管是在预处理命令中还是C语句中, 最好对某个对象只有单一的定义. 在gcc中, 若宏出现了重定义, gcc会给出警告.(2) 在gcc中, 可在命令行中指定对象宏的定义:e.g.$ gcc -Wall -DMAX=100 -o tmp tmp.c相当于在tmp.c中添加" #define MAX 100".那么, 如果原先tmp.c中含有MAX宏的定义, 那么再在gcc调用命令中使用-DMAX, 会出现什么情况呢? ---若-DMAX=1, 则正确编译.---若-DMAX的值被指定为不为1的值, 那么gcc会给出MAX宏被重定义的警告, MAX的值仍为1.注意: 若在调用gcc的命令行中不显示地给出对象宏的值, 那么gcc赋予该宏默认值(1), 如: -DVAL == -DVAL=1(3) #define所定义的宏的作用域宏在定义之后才生效, 若宏定义被#undef取消, 则#undef之后该宏无效. 并且字符串中的宏不会被识别。

C语言中的编译预处理技术及其灵活运用

C语言中的编译预处理技术及其灵活运用

3收稿日期:199721226 魏灿秋 硕士,讲师。

研究方向:计算机应用。

蒲小琼 讲师。

C 语言中的编译预处理技术及其灵活运用魏灿秋 四川联合大学 蒲小琼 成都纺织专科学校 四川 成都(610064)摘 要 编译预处理是C 语言一个重要且特别的功能,在进行C 语言程序设计时,灵活使用编译预处理技术可使源程序模块化结构好,更加清晰和便于阅读,并易于调试和移植。

关键词 编译预处理,包含文件,宏定义,条件编译1 什么是编译预处理在C 语言的编译系统中存在预处理程序模块,其功能是:在对一个源程序进行编译时,预处理程序首先对源程序进行扫描,对C 语言中的几种预处理语句进行分析和处理。

经过预处理之后,才进行正式编译以形成目标代码。

书写源程序时,一般将预处理语句置于开头部分,每一条预处理语句以“#”开始。

C 语言的初学者都会遇到必须使用的包含文件语句“#include ”就属于预处理语句。

预处理语句主要有包含文件、宏定义、条件编译三类。

对包含文件,预处理程序要将被包含的文件之源代码嵌于被编译程序的相应位置,参加正式的编译以目标代码生成;对宏定义,预处理程序要对相应符号进行宏替换;对条件编译,预处理程序要根据条件确定源程序中的哪些部分要参加正式编译形成目标代码,哪些部分不形成目标代码。

以下就三类预处理语句进行分别讨论。

2 包含文件语句#includeC 语言的初学者一开始都会接触到#include 语句,即使是最简单的C 语言程序也需要将象stdi o .h 这样的文件包含入自己所设计的源程序之中。

但许多有关C 语言程序设计的书中未明确说明编译程序对它的处理方法。

预处理程序对#include 语句的处理方法是:将#include 语句所指的文件(源程序)代码完全嵌于被编译程序中#include 所在的位置,以参加正式编译形成目标代码。

包含文件语句的一般形式为 #include 〈文件名〉或#include “文件名”我们在进行一个C 语言编译系统的安装时,一般要按安装步骤提示形成一个缺省包含文件搜索路径。

C语言课件—编译预处理

C语言课件—编译预处理

#include <stdio.h> #define sqr(x) ((x)*(x))
#include "powers.h" #define cube(x) ((x)*(x)*(x))
void main() { int n调;试方法
#define quad(x) ((x)*(x)*(x)*(x))
print1f.("n编u辑mpboerw\teersx.ph2,保\t e存xp3\t exp4\n");
❖宏体及各形参外一般应加括号()
例 #define POWER(x) x*x
x=4; y=6;
z=POWER(x+y); 宏展开:z=x+y*x+y; 一般写成: #define POWER(x) 宏展开: z=((x+y)*(x+y));
((x)*(x))
Macro Definition
例. 带参数的宏与函数实现同样功能
第七章 编译预处理
概述 宏定义 文件包含 条件编译
Next chapter
Introduction
作用:编译程序的一部分,将特殊命令扩展到程 序中,生成扩展C源程序
种类
❖宏定义 #define ❖文件包含 #include ❖条件编译 #if--#else--#endif
格式:
❖“#”开头 ❖占单独书写行 ❖语句尾不加分号; ❖定义位置任意,决定其作用域
print2f.("-将---p\to-w---e\tr-s--.h--文\t-件---存--\n放"到); 某一目录下
for(n3=. 1;编n<辑=fMmAaXin;.nc,++将) powers.h包含进来
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#define S(a,b) a*b area=S(3,2); 定义宏名S代表矩形面积,参数a,b为边长。 宏展开过程:
ppt课件
7
9.2 文件包含处理 在一个源文件中将另一个源文件的内容包 含进来。 文件包含指令的一般形式: #include “文件名” 或 #include <文件名>
ppt课件
第九章 编译预处理
C语言提供了一些以#开头的指令,如:
#define #include 等。
这些指令是在编译以前就事先进行处理的,因 而称为“编译预处理”指令。
可以用编译预处理指令实现以下三种功能:
1) 宏定义
2) 文件包含
3) 条件编译
பைடு நூலகம்
ppt课件
1
9.1 宏定义 1、不带参的宏定义 用一个指定的标识符(宏名)代表一个字符串。 一般形式: #define 标识符 字符串 如:#define PI 3.1415926 有了这一宏定义后,程序中凡是用到3.1425926 的地方都可以以宏名PI出现。
f.h
#define PI 3.1415926 float f1(float r); float fac(int n);
ppt课件
11
此课件下载可自行编辑修改,供参考! 感谢您的支持,我们努力做得更好!
——宏展开。
ppt课件
3
例:定义一个宏名来代表一个数据个数。eg9-02.c #define N 100 main() { int a[N],i; float s=0;
for(i=0;i<N;i++)scanf(“%d”,&a[i]); for(i=0;i<N;i++)s+=a[i]; s/=N; printf(“\n %f”,s); } 宏名N---符号常量,可以作为数组说明的长度。 方便修改参数。
ppt课件
5
注意以下程序的运行结果: eg9-04.c
#define F1 x+y
#define F2 (x+y)
main()
{ int x=3,y=5,z1,z2;
z1=2*F1;
z2=2*F2;
printf(“\n %d”,z);
}
ppt课件
6
2、带参的宏定义 宏定义也可以带参数,其一般形式为: #define 宏名(参数表) 字符串 如: eg9-05.c
8
file1.c
#include “file2.c”
file2.c
B
A
file1.c
B A
ppt课件
9
例:
#include “math.h”
main()
{ float a,b,c,s,area;
scanf(“%f%f%f”,&a,&,&c);
s=0.5*(a+b+c);
area=sqrt(s*(s-a)*(s-b)*(s-c));
ppt课件
4
例:定义一个宏名来代表一个计算公式。eg9-03.c #define PI 3.1415926 #define AREA PI*r*r main() { float r=3,s;
s=AREA; printf(“\n %f”,s); } 注意:系统对宏定义的预处理是一个字符串的还原过 程,不要把宏名看成一个整体。
ppt课件
2
例:定义一个宏名来代表一个参数。eg9-01.c #define PI 3.1415926 main() { float r=1.0,c,s; c=2*PI*r; s=PI*r*r; ┈}
系统在对程序进行编译以前,首先将所有的编
译预处理指令进行预处理,对本例来说,就是
将程序中所有的宏名PI还原成3.1415926,
printf(“\n %f”,area);
}
ppt课件
10
f.c
#include “f.h” main() { printf(“\n%f”,f1(3.0)); printf(“\n %f”,fac(10)); } float f1(float r) { return(PI*r*r); } float fac(int n) { int i; float s=1; for(i=1;i<=n;i++) s*=i; return(s); }
相关文档
最新文档