C语言预处理指令

C语言预处理指令

C语言中允许在源程序中加入一些“预处理指令”,以改进程序设计环境,提高编程效率。这些预处理指令是由C标准建议的,但他不是C语言本身的组成部分,不能用C编译系统直接对它们进行编译(因为编译程序不能识别他们)。必须在对程序进行正式编译之前,先对程序中这些特殊的指令进行**“预处理**”(也称“编译预处理”或“预编译”)。把预处理指令进行的预处理工作,是由称为C预处理器的程序负责处理的。

C提供的预处理功能常用的主要有一下3种

1.宏定义

2.文件包含

3.条件编译

这些功能分别用宏定义指令文件包含指令条件编译指令来实现。为了与C语言相区别,这些指令以符号"#"开头,指令后面没有分号。

1.1宏定义

1.1.1 不带参数的宏定义

概念:不带参数的宏定义是比较简单的,就是用一个指定的标识符来代表一个字符串,它的一般形式为:

   #define   标识符    字符串

例:

 #define PI 3.1415926

作用

在本程序文件中用指定的标识符PI来代替3.1415926这个字符串。在进行预处理时,将程序中凡事在该指令以后出现的所有的PI都用3.1415926代替。因此把这个标识符称为
“宏名”,在预处理时将宏名替换成字符串的过程称为"宏展开"。#define就是宏定义指令。

说明:

①宏定义只是用宏名代替一个字符串,也就是简单的置换,不作正确性检查。
如写成

   #define PI 3.14l5926

预处理时不作任何语法检查,只有对已被宏展开后的源程序进行编译时才会发现语法错误并报错。

②宏定义不是C语句,不用在结尾加分号,如果加了分号则一起进行置换。

   #define PI 3.1415926
   area=PI*r*r;

经过宏展开后,改语句应为:

area=3.1415926;*r*r;

③#define 指令出现在程序中的函数的外面,宏名的有效范围为该指令行起打本源文件结束。通常,#define 指令写在文件开头,函数之前,作为文件的一部分,在整个文件范围内有效。

④可以用#undef指令终止宏定义的作用域。例如:

#define G 9.8
int main()
{
    ...
}
//G的有效范围到此结束
#undef G    
f1()
   {
     ...
} 

⑤再进行宏定义时,可以引用已定义的宏名,即可以层层置换。

⑥在程序中用双撇号括起来的字符串内的字符,即使与宏相同,也不进行置换。例如

printf("L=%f \n S=%f\n",L,S);

printf函数内有两个L。在双撇号内不被宏置换,另一个被置换。

宏定义与定义变量的含义不同,不分配存储空间。不带参数的宏定义只作简单的字符串替换,千万不要把宏名当作变量名使用。

1.1.2带参数的宏定义

带参数的宏定义不是进行简单的字符串替换,还要进行参数替换。其定义的一般形式为:

#define 宏名(参数表) 字符串

字符串中包含在括号中所指定的参数。例如:

#define S(a,b) a*b
...
area=S(3,2)

因此赋值语句置换为:

area=3 * 2 ;

说明:
①函数调用时,先求出实参表达式的值,然后代入形参。而使用带参数的宏只是进行字符替代。

②函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏置换则是在预处理阶段进行的,在置换时并不分配内存单元,不进行值的传递处理,也没有"返回值"的概念。

③对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也是无类型,只是一个符号代表,置换时,代入指定的字符串即可。定义宏时,字符串可以是任何类型的数据。

④调用函数只可得到一个返回值,而用宏可以设法得到几个结果。

⑤使用宏次数多了,宏展看后源程序变长,因为每展开一次都使程序增长,而函数调用不会使源程序变长。

宏替换不占运行时间,只占预处理时间,而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。

1.2“文件包含”处理

#include"文件名"

所谓"文件包含"处理是指一个源文件可以将另外一个源文件的全部内容包含进来, 即将另外的文件内容包含到本文之中,插入到当前的位置。C语言用#include指令来实现“文件包含”的操作。其一般形式为:

#include"文件名"

#incldue <文件名>

这两者的区别在于:

用尖括号(如<stdio.h>)形式时,系统到存放C库函数头文件的目录中寻找要包含的文件,这称为标准方式

用双撇号(“file2.h”)形式时,系统先在用户当前目录中寻找要包含的文件,若找不到,再按标准方式查找。

说明:
①一个#include 指令只能指定一个被包含文件,如果要包含n个文件,要用n个#include 指令。

②如果文件1需要包含文件2,文件2 又要用到文件3,则可在文件1中用到两个 #include 指令分别包含文件2和文件3,并且文件3应出现在文件2之前,即在file1.c中定义 :

#include "file3.h"
#include "file2.h"

由于file3.h的位置在file2.h之前,file2和file1都可以用file3.h的内容。

③头文件除了可以包含函数原型和宏定义外,也可以包含结构体类型定义和全局变量定义等。

1.3条件编译

条件编译的以下三种形式:

第一种:

#ifdef 标识符
      程序段1
#else
      程序段2
#endif      

它的作用是:若所指的标识符以及被#define 指令定义过,则在程序编译阶段对程序段1 进行编译;否则编译程序段2。即在最后提供编译的源程序中只包含程序段1,或只包含程序段2。

条件编译中的#else部分可以没有,即:

#ifdef 标识符
   程序段
#endif

这里的“程序段”可以是语句组,也可以是指令行。这种条件编译对于提高C源程序的通用性是很有好处的。如果一个C源程序在不同计算机系统上运行,而不同的计算机又有一定的差异(有的机器以16位来存放一个整数),而有的则以32位存放一个整数,在这样的不同计算机上编译程序时往往需要对源程序作必要的修改,这就降低了程序的通用性。可以用以下的条件编译来处理:

#ifdef COMPUTER_A
    #define INTEGER 16
#else
    #define INTEGER_SIZE 32
#endif

第二种

#ifndef 标识符 
       程序段1
  #else
       程序段2
   #endif

同第一种形式相比,只是第一行不同:将ifdef
改成ifndef。它的作用是:若指定的标识符未被定义过,则编译程序段1;否则编译程序段2。这种形式与第一种的形式相反。

第三种

#if 表达式
    程序段1
#else
    程序段2
#endif

它的作用是当指定的表达式值为真(非零)时就编译程序段1;否则编译程序段2。可以事先给定条件,使程序在不同的条件下执行不同的功能。

本文来源:《C程序设计》谭浩强

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值