预处理命令详解
第九章 预处理命令
2、文件包含(1)
概念: 概念:一个源文件将另一个源文件全部内容包含进来 包含文件名” 一般格式: 一般格式: # include “包含文件名” 包含文件名 或 包含文件名> # include <包含文件名 包含文件名 两种格式的区别: 两种格式的区别:
双引号:系统先到当前目录下查找被包含文件,如果没找到, 双引号:系统先到当前目录下查找被包含文件,如果没找到,再到 系统指定的“包含文件目录” 在环境变量中设置) 系统指定的“包含文件目录”(在环境变量中设置)去查 找 尖括号:直接到系统指定的“包含文件目录” 尖括号:直接到系统指定的“包含文件目录”去查找双引号较可
关于#ifndef #endif命令 命令: 关于#ifndef ~ #endif命令:
格式相同,功能正好与之相反。 格式相同,功能正好与之相反。
#if ~ #endif
一般格式: 一般格式: #if 常量表达式 程序段1 程序段1;
[#else 程序段2 程序段2;] #endif 功能:当表达式为非0 逻辑真” 编译程序段1 功能:当表达式为非0(“逻辑真”)时,编译程序段1, 否则编译程序段2 否则编译程序段2。
2、文件包含(2)
说明: 说明:
编译预处理时,预处理程序将查找指定的被包含文件, 并将其复制到 #include 命令出现的位置上
通常将被包含文件称为“标题文件”或“头部文件”, 以“h”(head)作为后缀,简称头文件。在头文件中可 包含宏定义、外部变量定义、结构类型定义等 一条包含命令,只能指定一个被包含文件 文件包含可以嵌套,即被包含文件中又包含另一个文件
二、三种编译预处理
1、宏定义与符号常量 2、文件包含 3、条件编译
三、作业 第八部分 宏 定 义
【转】常用的预处理命令总结
【转】常⽤的预处理命令总结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 is used as an example”3. #error#error指令强制编译程序停⽌编译,它主要⽤于程序调试。
#error指令的⼀般形式是:#error error-message注意,宏串error-message不⽤双引号包围。
遇到#error指令时,错误信息被显⽰,可能同时还显⽰编译程序作者预先定义的其他内容。
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"文件名"在前面我们已多次用此命令包含过库函数的头文件。
C语言中的预处理指令
C语言中的预处理指令在C语言编程中,预处理指令是一种特殊的指令,用于在编译阶段之前对源代码进行处理。
预处理指令以井号(#)开头,并且不是被编译器执行的实际指令,而是由预处理器处理的。
本文将详细介绍C语言中的预处理指令,并探讨其在程序开发中的作用和用法。
一、什么是预处理指令预处理指令是在编译阶段之前对源代码进行处理的指令。
它的作用是在编译之前对源文件进行一些文本替换、条件编译或者简单的文本粘贴工作。
预处理指令以井号(#)开头,且位于编译单位(源文件或头文件)的最开始位置。
二、预处理指令的作用1. 宏定义宏定义是预处理指令中使用最广泛的功能之一。
通过宏定义,可以为一段代码或者一个常量起一个易于记忆和使用的名字,从而提高代码的可读性和维护性。
下面是一个宏定义的示例:```c#define MAX_NUM 100```在这个例子中,宏定义了一个名为MAX_NUM的常量,它的值为100。
在后续的代码中,可以使用MAX_NUM来代表100,避免了重复书写代码的问题。
2. 文件包含预处理指令还可以使用#include指令将其他文件的内容包含到当前文件中。
这种方式可以在不同的源文件中共享代码,提高代码的复用性。
下面是一个文件包含的示例:```c#include <stdio.h>```通过#include指令,可以将系统库文件stdio.h中的代码包含到当前文件中,以便后续代码可以使用stdio.h中定义的函数和类型。
3.条件编译条件编译是预处理指令中非常重要的概念。
通过条件编译,可以根据条件的真假选择性地编译代码。
这在不同的操作系统、不同的编译器或者不同的编译选项下具有重要的意义。
下面是一个条件编译的示例:```c#ifdef DEBUGprintf("Debug mode\n");#endif```在这个例子中,只有在编译时定义了DEBUG宏的情况下,才会编译并执行printf语句。
C语言中的预处理详解
C语言中的预处理详解目录一.预处理的工作方式 (3)1.1.预处理的功能 (3)1.2预处理的工作方式 (3)二.预处理指令 (4)2.1.预处理指令 (4)2.2.指令规则 (4)三.宏定义命令----#define. 43.1.无参数的宏 (4)3.2带参数的宏 (5)3.3.预处理操作符#和##. 63.3.1.操作符#. 63.3.2.操作符##. 6四.文件包含------include. 6五.条件编译 (7)5.1使用#if 75.2使用#ifdef和#ifndef 95.3使用#defined和#undef 10六.其他预处理命令 (11)6.1.预定义的宏名 (11)6.2.重置行号和文件名命令------------#line. 11 6.3.修改编译器设置命令 ------------#pragma. 12 6.4.产生错误信息命令 ------------#error 12 七.内联函数 (13)在嵌入式系统编程中不管是内核的驱动程序还是应用程序的编写,涉及到大量的预处理与条件编译,这样做的好处主要体现在代码的移植性强以及代码的修改方便等方面。
因此引入了预处理与条件编译的概念。
在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令。
预处理命令属于C语言编译器,而不是C语言的组成部分。
通过预处理命令可扩展C语言程序设计的环境。
一.预处理的工作方式1.1.预处理的功能在集成开发环境中,编译,链接是同时完成的。
其实,C语言编译器在对源代码编译之前,还需要进一步的处理:预编译。
预编译的主要作用如下:●将源文件中以”include”格式包含的文件复制到编译的源文件中。
●用实际值替换用“#define”定义的字符串。
●根据“#if”后面的条件决定需要编译的代码。
1.2预处理的工作方式预处理的行为是由指令控制的。
这些指令是由#字符开头的一些命令。
#define指令定义了一个宏---用来代表其他东西的一个命令,通常是某一个类型的常量。
预处理命令
二、表演区 (一)什么是表演区 表演区以幼儿表演游戏为设计核心,通过道具吸引幼儿积极参加故事表 演、游戏等活动。 (二)表演区的环境布置与材料投放 表演区可以分为固定式和活动式表演区角两类。 固定式的表演区角是指在活动室内辟出一定区域,存放表演所需要的用 具。 活动式的表演区角则是根据表演需要,临时在走廊、门厅、过道或室外 等地方设置表演场所,便于及时放置和收拢。
第9章 预处理命令
• 9. 1 概述 • 9. 2 宏定义 • 9. 3 文件包含 • 9. 4 条件编译
9. 2 宏定义
• 9. 2. 1 无参宏定义
• 无参宏的宏名后不带参数。 • 其定义的一般形式为 • #define 标识符字符串 • 其中, #表示这是一条预处理命令; 凡是以#开头的指令均为预处理命
果果:“老师,一分钟是多久呢?” 教师:“就是一会儿,我一转身。” 贝贝:“我知道,最细的秒针走一圈,挺长的。” 佳佳:“一分钟就是我们从门口走到后面的窗子那里。” 教师:“一分钟能做什么?” 佳佳:“给花浇水。” 果果:“唱完一首歌。” 贝贝:“搬来一把椅子。”……
学习目标
1. 了解幼儿日常交谈的主要特点及指导要求。 2. 掌握语言区角的环境布置与材料投放要求,能科学地开展语言区角活 动的指导。 3. 学会设计听说游戏的玩法,并能评析幼儿园听说游戏。
上一页 下一页 返回
9. 2 宏定义
• 【例9 - 2】不作宏代换程序举例。
上一页 下一页 说明: • 虽然已定义宏名OK 表示100, 但在printf 语句中OK 被引号括起来, 因
此不作宏代换。 • 程序的运行结果为“OK”, 这表示把“OK” 当字符串处理。
上一页 下一页 返回
义时, 必须十分注意, 应保证在宏代换之后不发生错误。
预处理指令——精选推荐
预处理指令预处理命令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语⾔预处理命令的⼀种。
.net 预处理详解
.net 预处理详解在使用.net框架进行软件开发时,我们经常会遇到需要在编译阶段对代码进行预处理的情况。
预处理是指在编译代码之前,通过指定一些预处理指令来控制代码的编译过程。
预处理指令在代码中以`#`符号开头,告诉编译器应该如何处理代码。
在本文中,我们将详细介绍.net 框架中常用的预处理指令及其用法。
1. 条件编译条件编译是预处理中最常用的功能之一,它可以根据一些条件来决定是否编译一段特定的代码。
通过使用`#if`和`#endif`指令,我们可以在代码中嵌入任意条件来控制编译过程。
例如,我们可以使用条件编译来根据不同的操作系统平台编译不同的代码片段:```csharp#if WINDOWSConsole.WriteLine("This is a Windows platform.");#elif LINUXConsole.WriteLine("This is a Linux platform.");#endif```上述代码中,`#if`指令用于判断是否为Windows平台,如果是则输出相应的信息;`#elif`指令用于判断是否为Linux平台,如果是则输出相应的信息。
通过条件编译,我们可以根据具体情况选择性地编译代码,以实现更好的跨平台兼容性。
2. 定义常量预处理指令还可以用于定义常量,在编译过程中将其替换为指定的值。
通过`#define`指令可以定义一个常量,并在代码中使用该常量。
例如:```csharp#define MAX_VALUE 100int value = MAX_VALUE;```上述代码中,我们使用`#define`指令定义了一个名为`MAX_VALUE`的常量,并将其设置为100。
之后,在代码中使用该常量时,编译器会将其替换为实际的值。
这样可以提高代码的可读性和维护性。
3. 跳过代码有时候,在调试或者测试代码时,我们需要暂时跳过一些代码片段而不编译它们。
预处理命令
3
math.h——文件包含数学程序。 reg51.h——文件中包含51单片机的特殊寄存器定义。 reg52.h——文件中包含52单片机的特殊寄存器定义。 setjmp.h——文件包含定义jmp_buf类型和setjmp和longjmp程序原型。 stdarg.h——文件包含可变长度参数列表程序。 stdlib.h——文件包含存储区分配程序。 stdio.h——文件包含标准输入和输出程序。 string.h——文件包含字符串操作程序、缓冲区操作程序。 对于51单片机而言,源程序开头必须要包含reg51.h头文件,因为该文件对51单片 机的相关位及寄存器进行了定义,这样在程序中才可以正常使用寄存器等资源。
#else 程序段2
#endif 若常量表达式成立,则编译程序1,否则编译程序2。
5
单片机原理及应用
单片机原理及应用
C51语言中提供了各种预处理命令,其作用类似于汇编程序中的伪指令。在编译环 境对源程序进行编译前,需要先对程序中的预处理命令进行处理,然后将处理结果和源 程序一起编译。C51语言中的预处理命令包括宏定义命令、文件包含命令和条件编译命 令等。通常,除条件编译命令外,预处理命令一般放在函数体之外,并且通常都放置在 源文件的开头。
句如下:
outputs=0xff;
/*输出 1111 1111 */
进行编译时,预处理器会将整个程序中的所有outputs替换为P2。
2.文件包含命令
#include命令的功能是将指定的定义或声明文件放入程序之中,该命令常用于引入 标准库函数文件。下面是一些常用的C51头文件:
absacc.h——包含允许直接访问8051不同存储区的宏定义。 assert.h——文件定义宏,用来建立程序的测试条件。 ctype.h——包含字符转换和分类程序。 intrins.h——文件包含指示编译器产生嵌入式固有代码的程序原型。
预处理命令详解
预处理命令详解在编写程序的时候,我们经常要用到#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这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件只被被编译一次。
08_预处理命令
本章主要内容:宏定义文件包含条件编译1.1编译预处理编译预处理是在对源程序正式编译之前的处理,以“#”开头,如文件包含“#include”、宏定义“#define”等。
预处理命令不是C语言本身的组成部分,不能直接对它进行编译。
所有的预处理指令都是在编译之前完成的,不占用程序运行时间。
C语言提供了3中预处理功能,即宏定义、文件包含、条件编译。
以“#”开头,占用一个单独的书写行,语句结尾不适用分号。
宏定义:#define文件包含:#include条件编译:#ifndef…#if…#else…#endif等1.2宏定义1.2.1不带参数的宏定义语法格式:#define 宏名[宏体](宏体可省略,如果没有则作为一个标识用于#if语句中)功能:用指定标识符(宏名)代替字符序列(宏体)说明:宏名要是一个合法的标识符,通常采用大写字母表示;宏体可以是常数、表达式和语句,甚至可以是多条语句。
举例:#define PI 3.1415926 //定义π的值为3.1415926,以后要用到π,就可以直接用PI #define OUT printf(“Hello World!\n”); //定义宏OUT替换后面的函数用#undef可以终止宏名作用域,格式为:#undef 宏名举例:void main(){#define YES 1 //定义宏YESprintf("%d\n",YES);#undef YES //结束宏YES的作用域#define YES 0 //重新定义宏YESprintf("%d\n",YES);}有关宏定义的使用,需注意以下几点:1宏名习惯采用大写,以便与普通变量区分;2宏定义不是C语句,所以不能在行尾加分号;否则,宏展开时,会将分号也算在内3在宏展开时,预处理程序仅按宏定义简单替换宏名,不做任何检查。
如果有错误,只能由编译器在编译宏展开后的源程序时发现。
4宏定义的位置是任意的,宏名的有效范围是从定义命令处到本模块结束。
第七章 预处理命令
(6)宏定义允许嵌套 , 在宏定义的字符串中可以 宏定义允许嵌套, 宏定义允许嵌套 使用已经定义的宏名。 使用已经定义的宏名。在宏展开时由预处理程 序层层代换。 序层层代换。 例如: 例如: #define PI 3.1415926 #define S PI*y*y /* PI是已定义的宏名*/ 对语句: 对语句: printf("%f",S); 在宏代换后变为: 在宏代换后变为 printf("%f",3.1415926*y*y);
对于宏定义还要说明以下几点: 对于宏定义还要说明以下几点:
(1) 宏定义是用宏名来表示一个字符串,在宏展 宏定义是用宏名来表示一个字符串, 开时又以该字符串取代宏名, 开时又以该字符串取代宏名,这只是一种简 单的代换,字符串中可以含任何字符, 单的代换,字符串中可以含任何字符,可以 是常数,也可以是表达式, 是常数,也可以是表达式,预处理程序对它 不作任何检查。如有错误, 不作任何检查。如有错误,只能在编译已被 宏展开后的源程序时发现。 宏展开后的源程序时发现。
C语言提供了多种预处理功能,如宏定义、文件 语言提供了多种预处理功能,如宏定义、 包含、条件编译等。 包含、条件编译等。
7.1 宏定义
在C语言源程序中允许用一个标识符来表示一个 字符串,称为“ 字符串,称为“宏”。
#define M 50
被定义为“ 被定义为“宏”的标识符称为“宏名”。 的标识符称为“宏名” 在编译预处理时,对程序中所有出现的“宏名”, 在编译预处理时,对程序中所有出现的“宏名” 都用宏定义中的字符串去代换,这称为“ 都用宏定义中的字符串去代换,这称为“宏代 宏展开” 换”或“宏展开”。
(4)带参的宏和带参函数很相似,但有本质上的不同,除 带参的宏和带参函数很相似,但有本质上的不同, 带参的宏和带参函数很相似 上面已谈到的各点外, 上面已谈到的各点外,把同一表达式用函数处理与 用宏处理两者的结果有可能是不同的。 用宏处理两者的结果有可能是不同的。 【例7.6】 】 【例7.7】 】 void main() #define SQ(y) ((y)*(y)) { int i=1; void main() while(i<=5) { printf("%d\n",SQ(i++)); int i=1; } while(i<=5) int SQ(int y) printf("%d\n",SQ(i++)); { } return((y)*(y)); 1. (i++)*(i++)=1*2 i=3 2.(i++)*(i++)=3*4 i=5 } 2. (i++)*(i++)=5*6 i=7 3.(i++)*(i++)=7*8 i=9 5. (i++)*(i++)=9*10 i=10
预处理命令
第九章 编译预处理
所谓预处理就是C语言的编译系统在对程序进 行通常的编译之前,先对这些特殊的命令进行 预处理,然后将预处理的结果和源程序一起再 进行通常的编译处理,以得到目标代码。 C 语言的预处理主要有以下三种: 1. 宏定义 2. 文件包含 3. 条件编译 C的编译预处理命令以"#"开头
带参的宏定义在分析程序之前先进行宏展开, S((a+b),(c+d))展开时用(a+b)代替x,用(c+d)代 替y,展开的结果为:(a+b)*(c+d)
8
说明: (1)宏名一般用大写字母表示以便与变量 分开,但不是规定而只是习惯。
(2)宏定义不是C语句,末尾不加分号。 (3)程序中双引号中的宏名不进行宏替换。
4
无参的宏定义使用举例
#define M 10 main( ) {int j,a[M]; for(j=0;j<M;j++) a[j]=j+1; for(j=0;j<M;j++) printf("%6d",a[j]); }
无参宏定义中的宏名M系统是作为符号 常量来处理的,因此可以用来定义数组。
5
二、带参数的宏定义
格式: 说明: (1) 参数表中的参数必须为变量,称为形参。 (2) 带参的宏定义展开是从左到右依次将实参字符串 代替形参字符串。 (3) 在宏定义时,宏名与带参的括号之间不应 留空格,而括号后面一定要留空格。 (4) 宏定义与函数不同,务必要进行宏替换后 再分析程序的运行结果。 #define 标识符(参数表) 字符串
带参的宏定义在分析程序之前先进行宏展开, S(a+b,c+d)展开时用a+b代替x,用c+d代替y, 展开的结果为:a+b*c+d
第11章 预处理命令
程序员也可以把自己定义的符号常 量、宏,或函数原型放在头文件中, 用#include命令包含这些头文件。 (1)文件print_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"
3、如果“文件1”包含“文件2”,而“文件2” 又包含“文件3”,则可在 “文件1” 中使用 两个 include 命 令。
文件file1.c #include“file3.h” file3.h 应出现在 file2.h 之前 #include“file2.h”
4、文件包含可以嵌套。即一个被包含文件中 又可以包含另一个文件。
[例] 输出格式定义为宏 #define PR printf #define NL "\n"
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); }
[例] 返回多个值的宏定义。 #define PI 3.1415926 #define CIRCLE(R,L,S,V) L=2*PI*R; S=PI*R*R;V=4/3*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); }
预处理命令
预处理命令预处理命令的作用:对源程序编译之前做一些处理,生成扩展C源程序。
可以简化程序开发过程,提高程序的可读性,也更有利于移植和调试C语言程序。
一、宏定义1.不带参数的宏定义(1)格式:#define 宏名标识符宏内容字符序列(2)说明:①“#”开头;②占单独书写行;③行的尾部不以分号作为结束标记。
(3)宏展开(即宏替换)在用“宏内容字符序列”替换“宏名标识符”时,必须原样替换。
例如,有程序:#define NUM1 10#define NUM2 20#define NUM NUM1 + NUM2 main ( ){int a=2, b=3;a*=NUM; b=b*NUM;printf("a=%d, b=%d\n",a,b); }宏替换后程序内容如下:main ( ){int a=2, b=3;a*=10+20;b=b*10+20; /*初学者容易理解成b=b*(10+20); 从而得到错误的b值90*/ printf("a=%d,b=%d\n",a,b); }程序的运行结果为:a=60,b=50若想使b得到90的结果,可以将“#define NUM NUM1 + NUM2”改为“#define NUM (NUM1 + NUM2)”,即在“NUM1 + NUM2”外加一个(),从而在宏替换时,会将此括号原样展开出来。
【注意:程序中字符串常量即双引号中的字符与宏名相同时,不作为宏进行宏替换操作。
】例如,有程序:#define PRINT "Hello!"main(){printf("PRINT:%s\n",PRINT);} 宏替换后程序内容如下:main(){printf("PRINT:%s\n","Hello!");} 程序的运行结果是:PRINT: Hello!2.带参数的宏定义(1)格式:#define宏名标识符(参数列表)宏内容字符序列(2)说明:①参数列表由一个或多个参数构成,参数只有参数名,没有数据类型符,用逗号分隔②“宏内容字符序列”中通常会引用宏的参数(3)宏展开(即宏替换)首先将“宏内容字符序列”中的宏参数用实参替换,再将这个宏的实际内容文本替换掉源程序中的“宏名标识符(参数列表)”。
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语言第九章预处理命令
如果在程序中有下面的语句: 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 宏名(形式参数列表) 字符串
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在这个例子中,对于阅读该程序的人来说,符号MAX_NUM就有特定的含义,它代表的值给出了数组所能容纳的最大元素数目。程序中可以多次使用这个值。作为一种约定,习惯上总是全部用大写字母来定义宏,这样易于把程序红的宏标识符和一般变量标识符区别开来。如果想要改变数组的大小,只需要更改宏定义并重新编译程序即可。
6. #error指令
#error指令将使编译器显示一条错误信息,然后停止编译。
#error message :编译器遇到此命令时停止编译,并将参数message输出。该命令常用于程序调试。
#error指令 语法格式如下:
#error token-sequence
#error停止编译并显示错误信息
一、文件包含
#include预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。标准C编译器至少支持八重嵌套包含。
预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。这样就可以在多次包含同一个头文件时,通过给定编译时的条件来达到不同的效果。例如:
预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:
指令用途
#空指令,无任何效果
#include包含一个源代码文件
4.##运算符
##运算符用于把参数连接到一起。预处理程序把出现在##两侧的参数合并成一个符号。看下面的例子:
#defineNUM(a,b,c)a##b##c
#defineSTR(a,b,c)a##b##c
main()
{
printf("%d/n",NUM(1,2,3));
很显然,结果是10*11*12,而不是10*10*10;
那么怎样安全的使用Cube宏呢?必须把可能产生副作用的操作移到宏调用的外面进行:
intnum=8+2;
volume=Cube(num);
num++;
#endif
这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。
其实就是在编译的时候输出编译错误信息token-sequence,从方便程序员检查程序中出现的错误。
简单的例子
#include "stdio.h"
三、条件编译指令
条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。
1.#if指令
#if指令检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else、#elif或#endif为止;否则就不编译。
#define定义宏
#undef取消已定义的宏
#if如果给定条件为真,则编译下面代码
#ifdef如果宏已经定义,则编译下面代码
#ifndef如果宏没有定义,则编译下面代码
#elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#endif结束一个#if……#else条件编译块
采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。一个应用程序既包含编译器提供的公共头文件,也包含自定义
的私有头文件。采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。
#defineCube(x)(x)*(x)*(x)
可以时任何数字表达式甚至函数调用来代替参数x。这里再次提醒大家注意括号的使用。宏展开后完全包含在一对括号中,而且参数也包含在括号中,这样就保证了宏和参数的完整性。看一个用法:
intnum=8+2;
volume=Cube(num);
展开后为(8+2)*(8+2)*(8+2);
预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。
在C语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。
如果去掉#define语句,效果是一样的。
3.#ifdef和#ifndef
#defineDEBUG
main()
{
#ifdefDEBUG
printf("yes/n");
#endif
#ifndefDEBUG
printf("no/n");
int main(int argc, char* argv[])
{
#define CONST_NAME1 "CONST_NAME1"
printf("%s/n",CONST_NAME1);
#undef CONST_NAME1
#ifndef CONST_NAME1
printf("%s/n",STR("aa","bb","cc"));
}
最后程序的输出为:
123
aabbcc
千万别担心,除非需要或者宏的用法恰好和手头的工作相关,否则很少有程序员会知道##运算符。绝大多数程序员从来没用过它。
main()
{
#ifdefDEBUG
printf("Debugging/n");
#else
printf("Notdebugging/n");
#endif
printf("Running/n");
}
5.#elif指令
#elif预处理指令综合了#else和#if指令的作用。
six=(ONE+TWO)*TWO;
如果没有那个括号,就转换成six=ONE+TWO*TWO;了。
宏还可以代表一个字符串常量,例如:
#defineVERSION"Version1.0Copyright(c)2003"
2.带参数的#define指令
带参数的宏和函数调用看起来有些相似。看一个例子:
#endif
当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:
#ifdef XXX
...
#error "XXX has been defined"
#else
二、宏
宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换成宏定义时的值。宏最常见的用法是定义代表某个值的全局符号。宏的第二种用法是定义带参数的宏,这样的宏可以象函数一样被调用,但它是在调用语句处展开宏,并用调用时的实际参数来代替定义中的形式参数。
1.#define指令
#endif
在程序中包含头文件有两种格式:
#include<my.h>
#include"my.h"
第一种方法是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种方法是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。
#defineTWO
main()
{
#ifdefONE
printf("1/n");
#elifdefinedTWO
printf("2/n");
#else
printf("3/n");
#endif
}
程序很好理解,最后输出结果是2。
ห้องสมุดไป่ตู้
3.#运算符
出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。有时把这种用法的#称为字符串化运算符。例如:
#definePASTE(n)"adhfkj"#n
main()
{
printf("%s/n",PASTE(15));
}
宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。所以输出应该是adhfkj15。
2.#endif指令
#endif用于终止#if预处理指令。
#defineDEBUG0
main()
{
#ifDEBUG
printf("Debugging/n");