C/C++
进阶
Point 1
预处理程序与宏
我们都很清楚,宏的作用是给标识符或常量定义另外的名字(代号)。而预处理宏呢?看下面的例子:
//------------------file.h-----------------
#ifndef _CLIST_H_
#define _CLIST_H_
//body of file1.h
#endif
//--------------------------------------------
我们都知道它是给编译器读的。从这段语句编译器了解到:假如宏
_CLIST_H_
没有定义的话那就定义之,并且我将编译正文
body
。如果
_CLIST_H_
已经定义了,我将不编译正文
body
。字面意思确实是这样的,但为什么要这样做呢?假如去掉预处理宏呢?考虑下面例子:
//------------------file1.h-----------------
//body of file1.h
//--------------------------------------------
//-------------------file2.h-------------
#include “file1.h”
//body of file2.h
//----------------------------------------
//-------------------main.c-------------
#include “file1.h”
#include “file2.h”
//body of main.c
//----------------------------------------
根据include的包含关系,将main.c展开:
//-------------------main.c-------------
*//body of file1.h
*//body of file1.h
//body of file2.h
//body of main.c
//----------------------------------------
请注意下划线!该两项为#include “file2.h”的展开。
注意到带*号重复的两项。显然file1.h被重复包含,重复编译。这只是对头文件而言,对只有变量或函数声明的头文件而言。假如file1.h里有变量或函数的定义会发生什么情况呢?请您仔细想想。
结论:#ifndef…#define…#endif的使用保证源文件编译的一次性。
下面举个宏代换的例子:
#define CUBE(x) ((x)*(x)*(x))
对于调用
int x = 3; CUBE(++x)
;
会是什么结果?
它将生成
((++x)*(++x)*(++x))
,即6*6*6,而不是4*5*6。
解释:宏代换的使用我们很清楚,但对于同一个存储变量x,在3个++x之后,值为6。4*5*6认为3个++x为独立的不同变量。
除此之外,还有#undef(撤消宏定义)#else(预处理条件转折)#if !define(同#ifndef)#include(引入文件)#elif(同#else #if)等等。
更多更详细的预处理及宏的用法请参看《The C programming language》
自述:本文所用例子均出自练习项目:Code Statistic Assistant。你可以下载以便参考。该项目我做了两个版本,C和C++,均在VC++6.0下编译通过。核心算法采用课程练习——编译原理——的注释扫描算法以及代码行数统计算法。该项目并没有使用什么高深的算法及理论,所涉及的都是最基本的知识,并且我也不打算把它做得十分优雅和完美,只求能达到熟悉,加深程序设计思维锻炼的目的。这两个版本的实现都用到了命令解释模块,而且初步引入了命令消息的概念。你能从源文件里找到该消息的定义及使用,它和命令解释模块关系密切。该项目用到Win32 API的几个文件函数,本文不对其进行叙述,请参看相关API参考资料。
如果发现什么问题请联系:sense_8@163.com
下载首页:
C
版本:
C++
版本:
http://www.codeproject.com/Purgatory/Code_Statistic_Assistant/Code_Statistic_Assistant/CSA082_VerCpp.zip
参考资料:
《The C Programming Language》 K & R
《The C++ Programming Language》 Bjarne Stroustrup
《Expert C Programming—Deep C Secrets》 Peter Vander Linden