第10章 预处理命令

合集下载

02-预处理命令

02-预处理命令

预处理命令预处理预处理是指在进行编译之前所作的工作 以#开始的命令#include#define宏定义、文件包含、条件编译无参数宏用一个标识符来表示一个字符串,称为“宏” 被定义为“宏”的标识符称为“宏名”“宏代换”或“宏展开”无参宏的宏名后不带参数。

其定义的一般形式为 #define 标识符字符串“字符串”可以是常数、表达式、格式串#define M (y*y+3*y)对宏的说明宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。

如有错误,只能在编译已被宏展开后的源程序时发现。

宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。

宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。

如要终止其作用域可使用# undef命令。

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

宏定义允许嵌套#define PI 3.1415926#define S PI*y*y /* PI是已定义的宏名*/带参宏定义在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。

#define 宏名(形参表) 字符串#define M(y) y*y+3*y /*宏定义*/……k=M(5); /*宏调用*/带参数宏的注意问题带参宏定义中,宏名和形参表之间不能有空格出现。

例如#define MAX(a,b) (a>b)?a:b写为:#define MAX (a,b) (a>b)?a:b在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。

在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

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

文件包含文件包含命令行的一般形式为:#include"文件名"在前面我们已多次用此命令包含过库函数的头文件。

预处理命令详解

预处理命令详解

预处理命令详解在编写程序的时候,我们经常要用到#pragma指令来设定编译器的状态或者是指示编译器完成一些特定的动作。

1. #pragma message指令message能够在编译消息输出窗口中输出相应的消息,这对于源代码信息的控制非常重要的。

格式如下:#pragma message(“消息文本”)编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。

当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的候进行检查,假设我们希望判断自己有没有源代码的什么地方定义了_X86这个宏可以用下面的方法:#ifdef _x86#pragma message("_x86 macro activated!")#endif当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示"_x86 macro activated!"。

2. #pragma code_seg指令格式如下:#pragma code_seg([[{push |pop},][identifier,]]["segment-name",]["segment-class"])该指令用来指定函数在.obj文件中存放的节,观察.obj文件可以使用VC自带的dumpbin命令行程序,函数在.obj文件中默认的存放节为.text节。

(1)如果code_seg没有带参数的话,则函数存放在.txt节中;(2)push(可选参数):将一个记录放到内部编译器的堆栈中,可选参数(记录名)可以为一个标识符或者节名;pop(可选参数)将一个记录从堆栈顶端弹出,该记录可以为一个标识符或者节名;(3)identifier (可选参数):当使用push指令时,为压入堆栈的记录指派的一个标识符,当该标识符被删除的时候和其相关的堆栈中的记录将被弹出堆栈;(4)"segment-name" (可选参数):表示函数存放的节名;例如://默认情况下,函数被存放在.txt节中void func1() { // stored in .txt }//将函数存放在.my_data1节中#pragma code_seg(".my_data1")void func2() { // stored in my_data1 }//r1为标识符,将函数放入.my_data2节中#pragma code_seg(push, r1, ".my_data2)void func3() { // stored in my_data2 }int main() { }3. #pragma once指令格式如下:#pragma once这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件只被被编译一次。

预处理命令与结构体练习题答案

预处理命令与结构体练习题答案

第11章结构体与共用体一、选择题(在下列各题的A)、B)、C)、D)四个选项中,只有一个选项是正确的,请将正确选项填涂在答题卡相应位置上。

)11.1 C语言结构体类型变量在程序运行期间A)TC环境在内存中仅仅开辟一个存放结构体变量地址的单元B)所有的成员一直驻留在内存中C)只有最开始的成员驻留在内存中D)部分成员驻留在内存中考生答案: 正确答案: B11.2 下列各数据类型不属于构造类型的是A)枚举型 B)共用型 C)结构型 D)数组型考生答案: 正确答案: A11.3 当说明一个结构体变量时系统分配给它的内存是A)各成员所需内存量的总和 B)结构中第一个成员所需内存量C)成员中占内存量最大者所需的容量 D)结构中最后一个成员所需内存量考生答案: 正确答案: A11.4 设有以下说明语句typedef struct{ int n;char ch[8];} PER;则下面叙述中正确的是A)PER 是结构体变量名 B)PER是结构体类型名C)typedef struct 是结构体类型 D)struct 是结构体类型名考生答案: 正确答案: B11.5 已知有如下定义:struct a{char x; double y;}data,*t;,若有t=&data,则对data 中的成员的正确引用是A)(*t).data.x B)(*t).x C)t->data.x D)t.data.x 考生答案: 正确答案: B11.6 以下程序的运行结果是#include "stdio.h"main(){ struct date{ int year,month,day; } today;printf("%d\n",sizeof(struct date));}A)6 B)8 C)10 D)12考生答案: 正确答案: A11.7 设有如下定义:struck sk{ int a;float b;} data;int *p;若要使P指向data中的a域,正确的赋值语句是A)p=&a; B)p=data.a; C)p=&data.a; D)*p=data.a; 考生答案: 正确答案: C11.8 以下对结构体类型变量的定义中,不正确的是A)typedef struct aa{ int n;float m;} AA;AA tdl;B)#define AA struct aaAA { int n;float m;} tdl;C)struct{ int n;float m;} aa;struct aa tdl;D)struct{ int n;float m;} tdl;考生答案: 正确答案: C11.9 若有下面的说明和定义struct test{ int ml; char m2; float m3;union uu { char ul[5]; int u2[2];} ua;} myaa;则sizeof(struct test )的值是A)12 B)16 C)14 D)9考生答案: 正确答案: A11.10 以下程序的输出是struct st{ int x; int *y;} *p;int dt[4]={ 10,20,30,40};struct st aa[4]={ 50,&dt[0],60,&dt[0],60,&dt[0],60,&dt[0]};main(){ p=aa;printf("%d\n",++(p->x));}A)10 B)11 C)51 D)60考生答案: 正确答案: C11.11 有以下程序:#include <stdio.h>union pw{ int i;char ch[2];}a;main(){ a.ch[0]=13;a.ch[1]=0;printf("%d\n",a.i);}程序的输出结果是A)13 B)14 C)208 D)209 考生答案: 正确答案: A11.12 已知学生记录描述为:struct student{ int no;char name[20],sex;struct{ int year,month,day;} birth;};struct student s;设变量s中的“生日”是“1984年11月12日”,对“birth”正确赋值的程序段是A)year=1984;month=11;day=12;B)s.year=1984;s.month=11;s.day=12;C)birth.year=1984;birth.month=11;birth.day=12;D)s.birth.year=1984;s.birth.month=11;s.birth.day=12;考生答案: 正确答案: D11.13 有如下定义struct person{char name[9];int age;};struct person class[10]={"John",17,"paul",19,"Mary",18,"Adam",16,};根据上述定义,能输出字母M的语句是A)printf("%c\n",class[3].name);B)printf("%c\n",class[3].name[1]);C)printf("%c\n",class[2].name[1]);D)printf("%c\n",class[2].name[0]);考生答案: 正确答案: B11.14 下列程序的输出结果是struct abc{ int a, b, c, s; };main(){ struct abc s[2]={{1,2,3},{4,5,6}}; int t;t=s[0].a+s[1].b;printf("%d\n",t);}A)5 B)6 C)7 D)8考生答案: 正确答案: B11.15 若有下面的说明和定义,则sizeof(struct aa)的值是struct aa{ int r1; double r2; float r3;union uu{char u1[5];long u2[2];}ua;} mya;A)30 B)29 C)24 D)22考生答案: 正确答案: D11.16 有以下结构体说明和变量的定义,且指针p指向变量a,指针q指向变量b。

预处理指令——精选推荐

预处理指令——精选推荐

预处理指令预处理命令1 . 基本介绍使⽤库函数之前,应该⽤#include引⼊对应的头⽂件,这种以#开头的命令称为预处理命令这些在编译之前对源⽂件进⾏简单加⼯的过程,就称为预处理(即预先处理,提前处理)预处理主要是处理以#开头的命令。

例如#include<stdio.h>,预处理命令要放在所有函数之外,⽽且⼀般都放在源⽂件的前⾯预处理是C语⾔的⼀个重要功能,由预处理程序完成,当对⼀个源⽂件进⾏编译时,系统将⾃动调⽤预处理程序对源程序中的预处理部分做处理,处理完毕⾃动进⼊对源程序的编译C语⾔提供了多种预处理功能,如宏定义,⽂件包含,条件编译,合理的使⽤会使编写的程序便于阅读,修改,移植和调试,也有利于程序模块化设计2 . 快速⼊门2.1 具体要求开发⼀个C语⾔程序,让它暂停5秒以后再输出内容“hello 尚硅⾕”,并且要求跨平台,在Windows和Linux下都能运⾏2.2 提⽰Windows平台下的暂停函数的原型是void Sleep(DWORD dwMilliseconds),参数的单位是“毫秒”,位于<windows.h>头⽂件linux平台下暂停函数的原型是unsigned int sleep(unsigned int second),参数的单位是“秒”,位于<unistd.h>头⽂件if ,#endif ,就是预处理命令,他们都是在编译之前由预处理程序来执⾏的2.3 代码实现#include<stdio.h>//说明:在Windows操作系统和Linux操作系统下,⽣成源码不⼀样#incLude<windows.h>int main(){Sleep(5000);puts("hello ,尚硅⾕");getchar();rerurn 0;}#if_WIN32 //如果是windows平台,就执⾏#include<windows.h>#include<windows.h>#elif_linux_//否则判断是不是linux,如果是linux就引⼊<unistd.h>#include<unistd.h>#endifint main(){//不同的平台调⽤不同的函数#if_WIN32Sleep(5000);#elif_linux_sleep(5);#endifputs("hello,尚硅⾕");getchar();return 0;}3 . 宏定义3.1 基本介绍define叫做宏定义命令,它⼜是C语⾔预处理命令的⼀种。

预处理指令

预处理指令

预处理指令,宏和运算符当编译程序时,它做的第一件事是进行预处理。

这一阶段中,甚至可以人为地将编译器视为一个不同的实体——预处理器。

该阶段中,编译器读入头文件、决定编译哪些行的源代码并执行文本替换。

预编译阶段的优越性在于它的编译及运行之前执行了某些特定的操作。

这些操作并不添加额外的程序执行时间。

同时,这些命令也不与程序运行时所发出的任何指令相对应。

所以,在使用预处理指令时就需要兼顾实际的运行情况。

预处理的三个基本元素:指令:在程序编译前执行的特定命令。

预定义宏:在编译前所执行的特定命令。

预处理运算符:在#if和#define中使用。

预处理指令语法与C++的其它语法有所不同。

指令以行末结束,而不需要分号。

但你可以用续行符(\)来摆脱物理行的限制。

另外,指令必须从第一行开始。

指令:有一半预处理指令提供了对条件编译的支持,条件编译的作用是用来维护同一程序的不同版本。

这些指令包括:#if #ifdef #elif #ifndef #else #end其余的预处理指令提供了对其它功能的支持,例如包括头文件和宏定义:#define #include #pragma #error #line #undef详解:★#define [定义符号或宏]目的:一:提供了创建符号常量的有效信息途径。

二:使编写人员能写宏指令,这些宏指令看上去像函数调用,但实际上是通过文本替换来实现。

三:简单地定义某些符号作为#ifdef指令的开关。

语法格式:#define标识符替代值#define 标识符[(参数1,.....,参数n)] 替代值其中,在”替代值”中出现的形参将在使用时被实参替代. 就象写函数一样.#define 标识符◆用法一:符号常量有些程序用到了一些很重要但又非常难忘或难以输入的数字。

最好事先将它们转化成为符号常量。

在转化时,通常是以大写形式表示,以便将它们与变量名区分开来。

例:#define E 2.718281828459这条指令的意思是每当程序中出现E时,预处理器就会将E替换成2.718281828459。

10章 预处理命令

10章 预处理命令

第10章预处理命令10.1 知识要点回顾10.1.1 C语言的预处理在C语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。

要完成这些工作,就需要使用预处理程序。

尽管在目前绝大多数C语言的编译器都包含了预处理程序,但通常认为它们是独立于编译器的。

预处理过程先于编译器对源代码进行处理。

预处理过程扫描源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换,产生新的源代码提供给编译器。

预处理过程还会删除程序中的注释和多余的空白字符。

C语言的预处理指令是以#号开头的代码行。

#号必须是该行除了任何空白字符外的第一个字符。

#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。

整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。

C语言中常用的预处理指令包括:10.1.2 文件包含#include预处理指令的作用是在指令处展开被包含的文件。

包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。

标准C编译器至少支持八重嵌套包含。

在程序中包含头文件有两种格式:#include <my.h>#include "my.h"第一种方法是用尖括号把头文件括起来。

这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。

第二种方法是用双引号把头文件括起来。

这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。

采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。

一个应用程序既包含编译器提供的公共头文件,也包含自定义的私有头文件。

采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。

预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。

预处理指令

预处理指令

#include 指令
#include 指令的作用是指示编译器将该指令所指出的另一个源文件嵌入#include指令所在 的程序中, 文件应使用双引号或尖括号括起来. C 库函数的头文件一般用#include指令在程序开关说明. 例如: #include <stdio.h> 程序中也允许嵌入其它文件, 例如: main() { #include <help.c> } 其中help.c为另一个文件, 内容可为 printf("Glad to meet you here!"); 处理命令的格式 #include "包含文件名" 或 #include <包含文件名 包含文件名" 包含文件名> 包含文件名 包含文件名 两种格式的区别仅在于: (1)使用双引号:系统首先到当前目录下查找被包含文件,如果没找到,再到系统指定 的"包含文件目录"(由用户在配置环境时设置)去查找. (2)使用尖括号:直接到系统指定的"包含文件目录"去查找.一般地说,使用双引号 比较保险.
可变参数的函数
我们在C语言编程中会遇到一些参数个数可变的函数, 例如printf()这个函数,它的定义是这样的: int printf( const char* format, ...); 它除了有一个参数format固定以外,后面跟的参数的个数 和类型是可变的,例如我们可以有以下不同的调用方法: printf("%d",i); printf("%s",s); printf("the number is %d ,string is:%s", i, s); 究竟如何写可变参数的C函数以及这些可变参数的函数 编译器是如何实现的呢?现在就这个问题进行一些探讨,希望 能对大家有些帮助.

第10章-编译预处理ppt课件(全)

第10章-编译预处理ppt课件(全)
#include <stdio.h> #define M(x,y,z) x*y+z int main( ) { int a=1,b=2, c=3; printf(“%d\n”,M(a+b,b+c,c+a)); return 0; }
-8-
带参数的宏定义(续)
【例10-3】用宏来定义多个语句的例子。
宏的使用有很多好处,不仅可以简化程序的书写,而且便于程序的 修改和移植,使用宏名来代替一个字符串,可以减少程序中重复书写某 些字符串的工作量。
根据宏定义中是否有参数,可以将宏分为不带参数的宏定义与带参 数的宏定义两种,下面分别讨论这两种宏的定义与调用。
-4-
10.1.1 不带参数的宏定义
不带参数的宏的宏名后面没有参数,不带参数的宏定义又称简单宏 定义。其定义的一般形式为:
宏定义是用一个标识符来表示一个字符串,这个字符串可以是常量、变量或表 达式。在宏替换时,用该字符串代换宏名。根据宏定义中是否有参数,可以将宏分 为不带参数的宏定义与带参数的宏定义两种。在写带有参数的宏定义时,宏名与带 括号参数间不能有空格,否则将空格以后的字符都作为了替换字符串的一部分,这 样就变成不带参数的宏定义了。不要把带参数的宏定义与带参数的函数混淆,带参 的宏定义在预处理时只是字符串的替换,而带参的函数却是将实参的值一一对应的 传递给形参。
#define 宏名 字符串 其中,“#”表示预处理命令。define是关键字,表示该命令为宏定 义。为了与一般的普通变量相区别,宏名一般使用大写。“字符串”一 般为常量、表达式或字符串。 在进行预处理时,系统会将程序中的“宏名”用“字符串”来替换。
-5-Biblioteka 10.1.1 不带参数的宏定义

第10章 预处理命令

第10章  预处理命令

< >: 直接到系统指定的
A
预编译 处理后
A
源文件 prg1.cpp
B
源文件 prg2.cpp
B
新源文件 prg2.cpp
文件包含举例:
#include "head.h" #include "func.cpp" void main ( ) { int a , b, c; a = getnum ( ); b = getnum ( ); int max (int x, int y) c = max ( max(a, b), NUM ); { printf ("MAX = %d\n", c ); return (x > y ? x : y); } } #include <stdio.h> int #define (NUM 10 getnum ) 预编译 { int a; 处理后 scanf("%d", &a) return (a); }
本章讨论之 重点!
预处理命令
学习目标
掌握#include、#define、#if、#ifdef、#else、#ifndef和 #endif等命令的用法; 掌握宏定义和宏替换的一般方法; 掌握包含文件的处理方法; 了解条件编译的作用和实现方法。
学习内容
预处理命令简介 宏定义 不带参数的宏定义 带参数的宏定义 文件包括 条件编译 本章小结
z=POWER(x+y); 宏展开: z=x+y*x+y; 一般写成: #define POWER(x) ((x)*(x)) 宏展开: z=((x+y)*(x+y));
PI*r*r”

第10章 预处理命令

第10章  预处理命令
/*头文件user.h*/ /*头文件user.h*/
#define PI 3.1415 #include <stdio.h>
#include "user.h" #include "test2.c" #include "test3.c" main( ) { float r,s,l; printf("\nr=?"); scanf("%f",&r); s=area(r); l=circle(r); printf("The circle area is %f\n",s); printf("The circumference is %f\n",l); }
如果在它的前面定义过标识符"DBG",则在程 如果在它的前面定义过标识符"DBG",则在程 序运行时输出x,y的值,以便在程序调试时进 序运行时输出x,y的值,以便在程序调试时进 行分析。调试完成后只需将定义标识符"DBG" 行分析。调试完成后只需将定义标识符"DBG" 的宏定义命令删除即可。
#ifndef形式 #ifndef形式
10.2 宏定义
宏定义是用预处理命令#define实现 宏定义是用预处理命令#define实现 两种形式
– 不含参数的宏定义 – 含参数的宏定义
例10.1 给定半径,求圆面积 #include <stdio.h> 不带参数的宏 #define PI 3.14 #define R 3 #define AREA PI*R*R 格式:#define 格式:#define 宏名 字符串 void main() 例: {float area; #define PI area=AREA; 3.1415926 PI是宏名,字符串3.1415926 PI是宏名,字符串3.1415926 3.1415926是替换正文 printf("AREA is %f\n",area); 是替换正文 } 运行结果为: AREA is 28.260000 用一个有意义的标识符代替一个字符串,便 于记忆;易于修改(一改全改),提高程序 的可移植性。

预处理命令

预处理命令

10.2预处理指令主要有三种类型:1、宏定义:#define和#undef指令2、文件包含:#include指令3、条件编译:#if、#ifdef、#ifndef、#elif、#else和#endif指令宏定义包含带参数的宏和不带参数的宏两种;带参数的宏定义格式为:#define 标识符(X1,X2,X3…)替换列表其与函数调用的结果完全不同,详见12/22程序macro with parameter通过程序实例得出,为了避免宏名参与的运算结果不混淆,一般采用如下两种形式的定义方式:1、#define AREA(X)(X)*(X)2、#define AREA(X)(X*X)替代#define AREA(X)X*X避免在宏定义中使用自增符号,如对于宏定义#define AREA(X)(X*X),AREA(++X),被展开为++X*++X,假如X初值为5,则其运算结果可能为42或者49,由于未规定运算顺序,编译器可能会出现不同的结果宏定义与函数有类似的地方,宏代替函数有以下优点:1、从效率角度考虑,程序执行起来会更快些,在调用函数时总会有些额外的开销,如保存调用点的信息以便函数调用结束后能正确返回调用点,而宏调用则没有这些运行时的开销;2、宏更加通用。

与函数不同,宏的参数是没有类型的,因此,宏可以接收任何类型的参数,因此它的使用范围更加广泛同时,也会以下缺点:1、源程序编译后代码量会增加,预处理过程中会在每一处宏调用的地方插入宏的替换列表,显然会使源程序的代码增加;2、预处理器不会检查宏参数的类型,也不会进行类型转换,这样采用宏调用可能会产生错误的结果3、自增、自减运算不能在宏中进行,可能会导致错误的结果;#运算符和##运算符只能出现在带参数宏的替换列表中,例如x为一个宏的参数,那么#x就可以将参数名转化为相应的字符串,该过程称为字符串化(stringization),程序实例详见12.23 stringization##运算符,如果##连接的两个操作数中其中一个为宏的参数,那么会先进行参数替换,然后再执行##运算符的操作。

C语言-预处理命令

C语言-预处理命令

我们可以在C源程序中插入传给编译程序的各中指令,这些指令被称为预处理器指令,它们扩充了程序设计的环境。

现把常用的预处理命令总结如下:1. 预处理程序按照ANSI标准的定义,预处理程序应该处理以下指令:#if #ifdef #ifndef #else #elif#endif#define#undef#line#error#pragma#include显然,上述所有的12个预处理指令都以符号#开始,,每条预处理指令必须独占一行。

2. #define#define指令定义一个标识符和一个串(也就是字符集),在源程序中发现该标识符时,都用该串替换之。

这种标识符称为宏名字,相应的替换称为宏代换。

一般形式如下:#define macro-name char-sequence这种语句不用分号结尾。

宏名字和串之间可以有多个空白符,但串开始后只能以新行终止。

例如:我们使用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 \String that i s used as an example”3. #error#error指令强制编译程序停止编译,它主要用于程序调试。

#error指令的一般形式是:#error error-message注意,宏串error-message不用双引号包围。

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。

第十章 预处理命令

第十章 预处理命令

#define G 10.8 void main() { … } #undef G f1() { … }
_______ ↑ G的有效范围
-----↓----
在f1函数中,G不再代表 10.8。这样可以灵活控制 宏定义的作用范围。
C语言程序设计
说明:
(7)
在进行宏定义时,可以引用已定义的宏名,可以层层置换。
C语言程序设计
运行情况如下:
说明:
(1)对带参数的宏展开只是将语句中的宏名后面括号内的 实参字符串代替#define 命令行中的形参。 (2) 在宏定义时,在宏名与带参数的括弧之间不应加空 格,否则将空格以后的字符都作为替代字符串的一 部分。
C语言程序设计
带参数的宏和函数的区别:
(1) 函数调用时,先求出实参表达式的值,然后代入形参。而使 用带参的宏只是进行简单的字符替换。 (2) 函数调用是在程序运行时处理的,为形参分配临时的内存单 元。而宏展开则是在编译前进行的,在展开时并不分配内 存单元,不进行值的传递处理,也没有“返回值”的概念。 (3) 对函数中的实参和形参类型要求一致。而宏名无类型,它的 参数也无类型,只是一个符号代表,展开时代入指定的字 符串即可。宏定义时,字符串可以是任何类型的数据。 (4) 调用函数只可得到一个返回值,而用宏可以设法得到几个结 果。
• 所谓“文件包含”处理是指一个源文件可以将另外一个 源文件的全部内容包含进来。C语言提供了#include命 令用来实现“文件包含”的操作。
其一般形式为: #include "文件名" 或 #include <文件名>
C语言程序设计
【程序文本10.6 】将【程序文本10.5 】时格式宏做 成头文件,把它包含在用户程序中。 (1)将格式宏做成头文件 format.h #include <stdio.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" (2)主文件file1.c #include <stdio.h> #include "format.h" 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); }

C语言编程中的预处理命令你会用吗?

C语言编程中的预处理命令你会用吗?

C语言编程中的预处理命令你会用吗?什么是预处理命令预处理命令在我之前看过的C语言基础教程中好像并没有详细说到,在现在的一些项目中预处理命令的出现频率却越来越多。

事物的存在必有其存在的理由,于是就花时间去琢磨了一下,以及查阅相关资料,发现使用预处理命令去优化代码可以达到很好的效果。

预处理命令在某资料中是这样描述的'C程序的源代码中可包括各种编译指令,这些指令称为预处理命令。

虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境'。

预处理命令实质上是运行在编译器编译过程的指令。

所以说在嵌入式程序设计中使用预处理命令不会占用最终目标运行系统的存储空间。

预处理命令有哪些在ANSI标准定义的C语言预处理程序中包括下列命令:#include,#define,#if,#else,#elif,#endif,#ifdef,#ifndef,#error,#undef,#line,#pragma等。

从以上可以看出预处理命令的共同特点就是以'#'开头。

下面就分别介绍几个在项目中使用比较多的预处理命令。

1.#include这个预处理命令算是使用的最多而又最重要的一个预处理命令了。

它的作用你是否还记得?include就是'包含'的意思,在程序编译的时候预处理器看到#include就会把<>尖括号或者' '中的那个文件找到,然后用该文件的内容替换掉#include <>这一行。

使用方法或者格式:#include <xxx.h>2.#define#define叫做宏定义,标识符为所定义的宏名,简称宏。

标识符的命名规则与前面讲的变量的命名规则是一样的。

#define的功能是将标识符定义为其后的常量。

一经定义,程序中就可以直接用标识符来表示这个常量。

是不是与定义变量类似?但是要区分开!变量名表示的是一个变量,但宏名表示的是一个常量。

第10章 预处理命令

第10章  预处理命令

10.8 小结
本章首先描述了预处理器的工作过程,
并给出了一些会影响预处理指令的通用 规则。
接着针对预处理器的主要功能分别介绍
了宏定义、条件编译和文件包含三部分 内容,它们分别用宏定义命令、条件编 译命令和文件包含命令来实现。

谢谢大家!!!

空行 空行 从文件stdio.h中引入的行 空行 空行 空行 空行 main() { float a,b; printf("Enter value a:"); scanf("%f",&a); b=(a+20)* (3.0/5.0); printf("The value of b is: %f\n",b); }
10.2 预处理指令
预处理的指令主要类型有3种,具体如下: 1. 宏定义。
◦ #define和#undef指令。

2. 文件包含。
◦ #include指令
3. 条件编译。
◦ #if、#ifdef、#ifndef、#elif、#else和#endif指 令。
10.2 预处理指令
1. 所有的预处理指令都以#开头。 2. 预处理指令的各个符号之间可以插入任 意数量的空格或横向制表符。 3. 预处理指令总是在第一个换行符出现时 结束,除非明确指明下一行仍然属于该指 令。 4. 预处理指令可以在程序的任何位置出现。 5. 预处理指令的注释可以与该指令位于同 一行。
10.3.2 带参数的宏

假设定义了如下的宏: #define AREA(x) x*x 如果在后续的程序中出现了如下的语句: z=AREA(5); 那么预编译器会将其替换为: z=5*5;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第十章预处理命令所谓编译预处理是指,在对源程序进行编译之前,先对源程序中的编译预处理命令进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。

一、宏定义与符号常量在C语言中,“宏”分为无参数的宏(简称无参宏)和有参数的宏(简称有参宏)两种。

无参宏定义1.无参宏定义的一般格式#define 标识符字符串其中:“define”为宏定义命令;“标识符”为所定义的宏名,通常用大写字母表示,以便于与变量区别;“字符串”可以是常数、表达式、格式串等。

2.使用宏定义的优点(1)可提高源程序的可维护性(2)可提高源程序的可移植性(3)减少源程序中重复书写字符串的工作量例9.1 输入圆的半径,求圆的周长、面积和球的体积。

要求使用无参宏定义圆周率。

/*程序功能:输入圆的半径,求圆的周长、面积和球的体积。

*/#define PI 3.1415926 /*PI是宏名,3.1415926用来替换宏名的常数*/void main(){float radius,length,area,volume;printf("Input a radius: ");scanf("%f",&radius);length=2*PI*radius; /*引用无参宏求周长*/area=PI*radius*radius; /*引用无参宏求面积*/volume=PI*radius*radius*radius*3/4; /*引用无参宏求体积*/printf("length=%.2f,area=%.2f,volume=%.2f\n", length, area, volume);}3.说明(1)宏名一般用大写字母表示,以示与变量区别。

但这并非是规定。

(2)宏定义不是C语句,所以不能在行尾加分号。

否则,宏展开时,会将分号作为字符串的1个字符,用于替换宏名。

(3)在宏展开时,预处理程序仅以按宏定义简单替换宏名,而不作任何检查。

如果有错误,只能由编译程序在编译宏展开后的源程序时发现。

(4)宏定义命令#define出现在函数的外部,宏名的有效范围是:从定义命令之后,到本文件结束。

通常,宏定义命令放在文件开头处。

(5)在进行宏定义时,可以引用已定义的宏名。

(6)对双引号括起来的字符串内的字符,即使与宏名同名,也不进行宏展开。

符号常量在定义无参宏时,如果“字符串”是一个常量,则相应的“宏名”就是一个符号常量。

恰当命名的符号常量,除具有宏定义的上述优点外,还能表达出它所代表常量的实际含义,从而增强程序的可读性。

#define EOF -1 /*文件尾*/#define NULL 0 /*空指针*/#define MIN 1 /*极小值*/#define MAX 31 /*极大值*/#define STEP 2 /*步长*/有参宏定义1.带参宏定义的一般格式#define 宏名(形参表) 字符串2.带参宏的调用和宏展开(1)调用格式:宏名(实参表)(2)宏展开:用宏调用提供的实参字符串,直接置换宏定义命令行中、相应形参字符串,非形参字符保持不变。

3.说明(1)定义有参宏时,宏名与左圆括号之间不能留有空格。

否则,C编译系统将空格以后的所有字符均作为替代字符串,而将该宏视为无参宏。

(2)有参宏的展开,只是将实参作为字符串,简单地置换形参字符串,而不做任何语法检查。

在定义有参宏时,在所有形参外和整个字符串外,均加一对圆括号。

(3)虽然有参宏与有参函数确实有相似之处,但不同之处更多,主要有以下几个方面:1)调用有参函数时,是先求出实参的值,然后再复制一份给形参。

而展开有参宏时,只是将实参简单地置换形参。

2)在有参函数中,形参是有类型的,所以要求实参的类型与其一致;而在有参宏中,形参是没有类型信息的,因此用于置换的实参,什么类型都可以。

有时,可利用有参宏的这一特性,实现通用函数功能。

3)使用有参函数,无论调用多少次,都不会使目标程序变长,但每次调用都要占用系统时间进行调用现场保护和现场恢复;而使用有参宏,由于宏展开是在编译时进行的,所以不占运行时间,但是每引用1次,都会使目标程序增大1次。

二、文件包含1.文件包含的概念文件包含是指,一个源文件可以将另一个源文件的全部内容包含进来。

2.文件包含处理命令的格式#include “包含文件名”或#include <包含文件名>两种格式的区别仅在于:(1)使用双引号:系统首先到当前目录下查找被包含文件,如果没找到,再到系统指定的“包含文件目录”(由用户在配置环境时设置)去查找。

(2)使用尖括号:直接到系统指定的“包含文件目录”去查找。

一般地说,使用双引号比较保险。

3.文件包含的优点一个大程序,通常分为多个模块,并由多个程序员分别编程。

有了文件包含处理功能,就可以将多个模块共用的数据(如符号常量和数据结构)或函数,集中到一个单独的文件中。

这样,凡是要使用其中数据或调用其中函数的程序员,只要使用文件包含处理功能,将所需文件包含进来即可,不必再重复定义它们,从而减少重复劳动。

4.说明(1)编译预处理时,预处理程序将查找指定的被包含文件,并将其复制到#include命令出现的位置上。

(2)常用在文件头部的被包含文件,称为“标题文件”或“头部文件”,常以“h”(head)作为后缀,简称头文件。

在头文件中,除可包含宏定义外,还可包含外部变量定义、结构类型定义等。

(3)一条包含命令,只能指定一个被包含文件。

如果要包含n个文件,则要用n条包含命令。

(4)文件包含可以嵌套,即被包含文件中又包含另一个文件。

练习题一、选择题1.以下叙述中正确的是________.A)在程序的一行上可以出现多个有效的预处理命令行B)使用带参的宏时,参数的类型应与宏定义时的一致C)宏替换不占用运行时间,只占用编译时间D)在以下定义中CR是称为“宏名”的标识符#define CR 0452.以下程序的运行结果是________.#define MIN(x,y) (x)<(y)?(x):(y)main(){int i=10,j=15,k;k=10*MIN(i,j);printf("%d\n",k);}A)10 B)15 C)100 D)1503.若有宏定义如下:#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)76 6 5 54.请读程序:#include <stdio.h></P< p>#define MUL(x,y) (x)*ymain(){int a=3,b=4,c;c=MUL(a++,b++);printf("%d\n",C);}上面程序的输出结果是__________.A)12 B)15 C)20 D) 165.对下面程序段:#define A 3#define B(A) ((A+1)*A)...x=3*(A+B(7));正确的判断是_________.A)程序错误,不许嵌套宏定义B)x=93C)x=21D)程序错误,宏定义不许有参数6.以下正确的描述是____________.A)C语言的预处理功能是指完成宏替换和包含文件的调用B)预处理指令只能位于C源程序文件的首部C)凡是C源程序中行首以"#"标识的控制行都是预处理指令D)C语言的编译预处理就是对源程序进行初步的语法检查7.在"文件包含"预处理语句的使用形式中,当#include后面的文件名用< >(尖括号)括起时,找寻被包含文件的方式是_______.A)仅仅搜索当前目录B)仅仅搜索源程序所在目录C)直接按系统设定的标准方式搜索目录D)先在源程序所在目录搜索,再按照系统设定的标准方式搜索8.以下不正确的叙述是。

A) 预处理命令都必须以“#”号开始B) 在程序中凡是以“#”号开始的语句行都是预处理命令行C) C语言在执行过程中对预处理命令行进行处理D) # define ABCD是正确的宏定义9.以下不正确的叙述是。

A) 宏替换不占用运行时间B) 宏名无类型C) 宏替换只是字符替换D) 宏名必须用大写字母表示10.以下正确的叙述是。

A) C语言的预处理功能是指完成宏替换和包含文件的调用B) 预处理命令只能位于C源程序文件的首部C) 凡是C源程序中行首以“#”标识的控制行都是预处理命令D) C语言的编译预处理就是对源程序进行初步的语法检查11.C语言的编译系统对宏命令的处理。

A) 在程序运行时进行的B) 在程序连接时进行的C) 和C程序中的其它语句同时进行编译的D) 在对源程序中其它语句正式编译之前进行的二、填空题1.C提供的预处理功能主要有三种,分别是、和。

2.设有以下宏定义:# define WIDTH 80# define LENGTH WIDTH+40则执行赋值语句:v= LENGTH*20;(v为int型变量)后,v的值是。

3.设有以下宏定义:# define WIDTH 80# define LENGTH (WIDTH+40)则执行赋值语句:k= LENGTH*20;(k为int型变量)后,k的值是 4.以下程序将数组a中的数据按逆序存放,请填空。

#define M 8main(){int a[M],i,j,t;for(i=0;i<M;i++)scanf("%d",a+i);i=0;j=M-1;while(i<j){t=*(a+i);____ 【12】____;*(___【13】___)=t;i++;j--;}for(i=0;i<M;i++)printf("%3d",*(a+i));}。

相关文档
最新文档