baizy77 发表于 2018-9-25 16:49:02

C++老鸟日记032 预处理宏并非一无是处

本帖最后由 baizy77 于 2018-10-1 21:00 编辑

版权声明---------------------------------------------------------------------------------------------------------------------该文章原创于Qter开源社区(www.qter.org)作者: 女儿叫老白 (白振勇)转载请注明出处!---------------------------------------------------------------------------------------------------------------------课程目录:《C++老鸟日记》目录本套课程属于:《C++跨平台开发干货》系列课程。-----------------------------------------------------------------------------
引言:----------------------------------------------------------------------------       在前面的讨论中,我们使用内联函数代替了预处理宏来减少函数压栈;使用const常量或者constexpr来代替宏常量定义,如此看来,预处理宏好像没啥卵用呢。其实不然,预处理红并非一无是处。我们来看一下预处理宏的几个特征:字符串定义、字符串拼接和标志黏贴。
正文:----------------------------------------------------------------------------       字符串定义和字符串拼接实际是相互关联的。字符串定义是利用#把标识符替换为把字符串。比如:#defineTRACESS(s)(cerr << __FILE__<< ", line: "<< __LINE__ << ", "<<#s << endl;)然后在代码中调用它:TRACESS(f(3));我们来看一下这个预处理宏:1,s是标识符2,cerr是std的标准错误输出(一般指终端)3, __FILE__宏和__LINE__宏是标准宏,前者输出当前执行的代码的文件名,后者输出当前代码行数。4, #s用来把标识符转换为字符串输出。比如下面的输出中,f(3)被原封不动的输出到了终端。它的运行输出如下:d:\xingdianketang\project\gui\src\chapter00\syncdir\main.cpp,line: 33, f(3)
那么标志黏贴是咋回事呢?标志黏贴实际是将字符串标志替换为代码中的标志,它的语法为:##标志。比如:#define COMSTRUCT(COMPO)TK_##COMPO如果我们调用COMSTRUCT(Breaker),展开后,变成:       TK_Breaker
在项目中的应用如下列代码中的宏MACRO_FUNC_GETCOMPONENT:----------------------------------------------------------------------------// 开关structTK_Breaker {       qint32   nID;                      // 序号       Jchar      szMingZi;      //名字       qint32   nDZCount;                   //开关累计动作次数
       TK_Breaker(){            wID = 0;                     szMingZi = '\0';             nDZCount = 0;                    };};
// 变压器structTK_Transformer{       int   nID;                      // 序号       Jchar      szMingZi;             //名字       Jfloat      fMVA;                   //额定容量(兆伏安)
       TK_Transformer(){            wID = 0;                     szMingZi = '\0;'             fMVA            = 0.f;       };};
// 开关static Juint16Offset_TK_KaiGuan[] = {       offsetof(TK_KaiGuan, wID),       offsetof(TK_KaiGuan, szMingZi),       offsetof(TK_KaiGuan, nDZCount),};
// 变压器static Juint16Offset_TK_Transformer[] = {       offsetof(TK_Transformer, wID),       offsetof(TK_Transformer, szMingZi),          offsetof(TK_Transformer, fMVA),};
#define   MACRO_FUNC_GETCOMPONENT(COMPNAME)                                                                                 \Jint32 CData::Get##COMPNAME(intnID, TK_##COMPNAME* p##COMPNAME)       \{                                                                                                               \             filter.Format("ID=%d", nID);                \       return GetDBValue(,filter,(Juint8*)p##COMPNAME, Offset_TK_##COMPNAME); \};// 获取数据库一条纪录Jint32CMSData::GetDBValue(const char* filter, Juint8* base, Juint16* offset){       ......       return ret;}----------------------------------------------------------------------------在上述代码中,为了避免针对Breaker和Transformer以及更多的部件编写类似代码,特地设计了宏MACRO_FUNC_GETCOMPONENT。针对Breaker,我们调用MACRO_FUNC_GETCOMPONENT(Breaker)。那么,宏展开后变成:Jint32 CData::GetBreaker(intnID, TK_Breaker* pBreaker) \{                                                                                                               \             filter.Format("ID=%d", nID);                \       return GetDBValue(filter,(Juint8*)pBreaker, Offset_TK_Breaker);    \};如果我们调用MACRO_FUNC_GETCOMPONENT(Transformer)。那么,宏展开后变成:Jint32 CData::GetTransformer(int nID, TK_Transformer * pTransformer)      \{                                                                                                               \             filter.Format("ID=%d", nID);                \       return GetDBValue(filter,(Juint8*) pTransformer, Offset_TK_Transformer);   \};这样,我们就不用针对不同的结构体来编写不同的代码了,而这些代码大部分都重复。

结语:----------------------------------------------------------------------------       看来,预处理宏还是有它的用武之地的,前提是我们使用得当。
参考资料----------------------------------------------------------------------------《C++编程思想》两卷合订本中文版(9.6章节),(美) BruceEckelChuck Allison著

页: [1]
查看完整版本: C++老鸟日记032 预处理宏并非一无是处