预处理命令知识点(面试点之一)
一、宏定义:
1.不带参数的宏定义: 一般形式如下:
#define 标识符 字符串
说明:
(1).宏名一般习惯用大写字母表示,以便与变量名相区别,但这并非规定,也可以用小写字母。
(2).使用宏名代替一个字符串,可以减少程序中重复书写某些字符串的工作量。使用宏定义,可以提高程序的通用性。
(3).宏定义是用宏名代替一个字符串,也就是作简单的置换,不作正确性检查。
(4).宏定义不是C语句,不必在行末加分号。如果加了分号则会连分号一起进行置换。
(5).#define命令出现在程序中函数的外面,宏名的有效范围定义命令之后到本源文件结束。通常,#define命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。
(6).使用#undef命令终止宏定义的作用域。
(7).在进行宏定义时,可以引用已定义的宏名,可以层层置换。
(8).对程序中用双撇号括起来的字符串内的字符,即使用与宏名相同,也不进行置换。
(9).宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。
2.带参数的宏定义:一般形式如下:
#define 宏名(参数表) 字符串
说明:
(1).对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替#define命令行中形参。
(2).在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为代替字符串发一部分。
带参宏定义与函数的不同主要有:
(1).函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。
(2).函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏展开则是在编译前进行的在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
(3).对函数中的实参和形参都要定义类型,而者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符串即可。宏定义时,字符串可以是任何类型的数据。
(4).调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
(5).使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长。
(6).宏替换不占运行时间,只占编译时间,而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。一般用宏来代表简短的表达式比较合适。
二、“文件包含”处理:
“文件包含”处理是指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。C语言提供了#include命令来实现“文件包含”的操作。一般形式:#include“文件名”或#include<文件名>。
说明:
(1).一个#include命令只能指定一个被包含文件,如果要包含n个文件,要用n个#include命令。
(2).如果文件1包含文件2,而文件2中要用到文件3的内容,则可在文件1中用两个#include命令分别包含文件2和文件3,而且文件3应出现在文件2之前。
(3).在一个被包含文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的。
(4).在#include命令中,文件名可以用双撇号或尖括号括起来。<>为标准方式:先寻找系统存放C库函数头文件所在目录中寻找要包含的文件。而""则是用用户自己编写的文件中找要包含的文件,节省资源和查找时间。
(5).被包含文件与其所在的文件,在预编译后已成为同一个文件,因此,如果被包含文件中有全局静态变量,它也在包含文件中有效,不必用extern声明。
三、条件编译:
一般情况下,源程序中所有的行否参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译条件,这就是“条件编译”。“条件编译”命令有以下几中形式:
(1).#ifdef 标识符
程序段1
#else
程序段2
#endif
它的作用是当所指定的标识符已经被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2,其中可以没有#else部分:
#ifdef 标识符
程序段1
#endif
(2).#ifndef 标识符
程序段1
#else
程序段2
#endif
将“ifdef”改为“ifndef”。它的作用是若标识符未被定义过则编译程序段1,否则编译程序段2。这种形式与第一种形式相反。
(3).#if 表达式
程序段1
#else
程序段2
#endif
它的作用是当指定的表达式值为真(非零)时就编译程序段1,否则编译程序段2,可以事先给定一定的条件,使程序在不同的条件下执行不同的功能。