VC中预处理指令与
宏定义的妙用(1)
作者:刘巍
Monday
,June24200211
:28AM
刚接触到MFC编程的人往往会被MFC向导生成的各种
宏定义和预处理指令所吓倒,但是预处理和
宏定义又是C语言的一个强大工具。使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能。
一个经典的例子
使用预处理与
宏定义最经典的例子莫过于加在一个头文件中以避免头文件被两次编译。试想这种的情况,有一个文件headerfile
.h它被包含在headerfile1
.h中,同时在headerfile2
.h中也被包含了,现在有一个CPP文件,implement
.cpp包含了headerfile1
.h和headerfile2
.h:
#include“headerfile1.h”
#include“headerfile2.h”
假设headerfile
.h中定义了一个全局变量iglobal。
intiglobal
;在编译的时候编译器两次编译headerfile,也就会发现iglobal被定义了两次,这时就会发生变量重定义的编译错误。
传统的解决办法是使用#ifdef以及#endif来避免头文件的重复编译,在上面的例子中,只需要加上这么几行:
#ifndefsmartnose_2002_6_21_headerfile_h
#definesmartnose_2002_6_21_headerfile_h
intiglobal
;#endif
仔细的考虑上面的
宏定义,会发现当编译器编译过一次headerfile
.h以后,smartnose_2002_6_21_headerfile_h这个宏就被定义了,以后对headerfile
.h的编译都会跳过int iglobal这一行。当然smartnose_2002_6_21_headerfile_h这个宏是可以任意定义的,但是这个宏本身不能和其它文件中定义的宏重复,所以MFC在自动生成的文件中总是使用一个随机产生的长度非常长的宏,但我觉得这没有必要,我建议在这个宏中加入一些有意义的信息,比方作者,文件名,文件创建时间等等,因为我们有时候会忘记在注释中加入这些信息。
在VC
.Net中我们不会再看见这些
宏定义了,因为在这里会普遍使用一个预处理指令:
#pragmaonce
只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
源代码版本控制
当我们为许多平台开发多个版本的时候预编译指令和
宏定义也能够帮我们的忙。假设我们现在为WINDOWS和
LINUX开发了一套软件,由于这两种系统的不同,我们不得不在程序控制源代码的版本。比方内存的分配,我们可以在
LINUX上使用标准C的malloc函数,但是我们希望在 WINDOWS上使用HeapAllocAPI。下面的代码演示了这种情况:
main
()
{………………
..#ifdef_WINDOWS_PLATFORM
HeapAlloc
(5
);#else
malloc
(5
);#endif
………………
..
}当我们在WINDOWS平台上编译此程序的时候,只需要定义_WINDOWS_PLATFORM这个宏,那么HeapAlloc这条语句就能够起作用了。这样就能够让我们在同一个文件中为不同的平台实现不同版本的代码,同时保持程序的良好结构。在许多情况下,我们还可以为一个方法使用不同的算法,然后用
宏定义来针对不同的情况选择其中的一个进行编译。这在MFC应用程序中是使用得最多的。最明显的就是文件中经常存在的
#ifdef_DEBUG
……………………
.somecode………
..#endif
这样的代码,这些代码在应用程序的调试版(DEBUG)中会发挥其作用。
#Pragma指令
在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。其格式一般为
#PragmaPara
其中Para为参数,下面来看一些常用的参数。
message参数。Message参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
#Pragmamessage(“消息文本”)
当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法
#ifdef_X86
#Pragmamessage(“_X86macroactivated!”)
#endif
当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86macroactivated
!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。
另一个使用得比较多的pragma参数是code_seg。格式如:
#pragmacode_seg(["section-name"[,"section-class"]])
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。
最后一个比较常用的就是上面所说的#pragmaonce指令了。
VC预定义的宏
在VC中有一类宏并不是由用户用#define语句定义的,而是编译器本身就能够识别它们。这些宏的作用也是相当大的。让我们来看第一个,也是MFC中使用得最频繁的一个
:__FILE__。
当编译器遇到这个宏时就把它展开成当前被编译文件的文件名。好了,我们马上就可以想到可以用它来做什么,当应用程序发生错误时,我们可以报告这个错误发生的程序代码在哪个文件里,比方在文件test
.cpp中有这样的代码:
try
{char
*p
=new
(char
[10
]);
}catch
(CException
*e
)
{TRACE
(“thereisanerrorinfile
:%s
/n”
,__FILE__
);
}在程序运行的时候,如果内存分配出现了错误,那么在调试窗口中会出现thereisanerrorinfile
:test
.cpp这句话,当然,我们还可以把这个错误信息显示在别的地方。
如果我们还能够记录错误发生在哪一行就好了,幸运的是,与__FILE__
宏定义一样,还有一个宏记录了当前代码所在的行数,这个宏是__LINE__。使用上面的两个宏,我们可以写出一个类似于VC提供的ASSERT语句。下面是方法
#defineMyAssert(x)/
if(!(x))/
MessageBox(__FILE__,__LINE__,NULL,MB_OK);
我们在应用程序中可以象使用ASSERT语句一样使用它,在错误发生时,它会弹出一个对话框,其标题和内容告诉了我们错误发生的文件和代码行号,方便我们的调试,这对于不能使用ASSERT语句的项目来说是非常有用的。
除了这两个宏以外,还有记录编译时间的__TIME__,记录日期的__DATE__,以及记录文件修改时间的__TIMESTAMP__宏。
使用这些预定义的宏,我们几乎可以生成和VC能够生成的一样完整的源代码信息报表。
结论
翻开MFC和
Linux的源代码,
宏定义几乎占据了半边天,消息映射,队列操作,平台移植,版本管理,甚至内核模块的拆卸安装都用
宏定义完成。毫不夸张的说,有些文件甚至就只能看见
宏定义。所以学习
宏定义,熟练的使用
宏定义对于学习C语言乃至VC都是非常关键的。
--------------------------------------------------------------------------------刘巍-高级程序员、软件设计师,精通VC
,VB
,COM
,PLATFORMSDK
,DDK,TCP
/IP。独立开发过多种windows应用程序,WDMUSB驱动程序,网络应用程序。熟悉加密技术,熟悉
LINUX下的C
/C
++开发。
分享到:
相关推荐
预处理和宏定义是C语言的一个强大工具,使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能。
VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量VC中如何定义全局变量...
一个很简单的代码 ...而且程序中如果有需要获得程序版本集信息的,只须使用Define.h中预先定义好的宏就可以了,而不用去查MSDN去调用一些复杂的API函数来获得版本号等。 具体请看代码,VC2008的工程
预定义,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了 3、#typedef指令 常用来定义一个标识符...
MFC 宏定义的详解,从此那些莫名其妙的宏在你面前了无秘密! <br>有了这份文档,MFC的宏就像是被扒光了衣服的女人
运用VC对数字图像进行处理,包括用DIB类显示图像,还包括一些图像的预处理:图像的灰度变化,直方图变化,二值变化,图像滤波(中值滤波,均值滤波),边缘检测等。
VC三维重建中图像预处理技术的实现.doc
使用这个文件可以高亮C++中的宏与结构体以及所有大写的标识符,也适用于Asm语法高亮。
VC 使用MMX指令集的例子,通过点击MMX按钮来调用相关的MMX指令集,具体请下载测试。
利用VC_开发图像采集卡与图像预处理库,利用VC_开发图像采集卡与图像预处理库
VC定义光标热区 VC定义光标热区 VC定义光标热区
VC++中,SAMPLE.DSM宏文件的使用说明,快速给函数添加描述说明框架,快速给多行代码进行注释
VC图像处理 DIB文件读写 预处理算法
ipconfig指令的实例,改了一下,需要什么兄弟姐妹们可以改回来~~
vc调试宏,详细讲解vc调试代码。对于对vc有一定了解,希望继续提高的同学很有帮助!
VC宏Macros收集,内含多个宏文件,有时候VC宏是一个很用用工具或命令!
vc2008路径宏。对于初学者来说,工程属性里有些宏会比较生涩,这个文档对你可能会有帮助。
VC6.0 多个常见错误指令 及其解决方法
值得一看学习VC MFC开发必须了解的常用宏和指令