




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
情况是这样的:App程序只提供了部分代码,B库有全部代码。B库的代码需要用到App里面定义的一些枚举量,现在需要将B库链接到App里。由于枚举量的定义中使用了编译开关来控制,而App具体打开了哪些开关未知,从而导致B库中如果直接#include App使用的头文件所得到的枚举值与App里面运行时所得到的枚举值不匹配。还是写个Demo程序来说吧,App的代码是这样的,首先是App.h这个双方都要用的头文件如下:#ifndef APP_H#define APP_H/* Value of ID_E is controlled by switch SWITCH_ID_CD If SWITCH_ID_CD is enabled, ID_E = 4, If SWITCH_ID_CD is disabled, ID_E = 2.*/typedef enum t_ID ID_A = 0, ID_B,#ifdef SWITCH_ID_CD ID_C, ID_D,#endif ID_E, ID_FID;#endif可以看到如果编译开关SWITCH_ID_CD 打开,则 ID_E = 4,否则ID_E = 2。BLib 的代码 BLib.c 如下:#define BLIB_C /* App.h is from App, and we have no idea of SWITCH_ID_CD is switched on or off */#include ./App/App.h/* Get value of id */int get_id_value(ID id) return (int)id; /* It will return 2 because SWITCH_ID_CD not defined in this lib */int get_ID_E() return get_id_value(ID_E);BLib.c 并没有打开编译开关 SWITCH_ID_CD,那么当App调用BLib的函数get_ID_E() 时,将会返回2。App的主程序App.c如下:/* Link BLib.lib in App */#pragma comment(lib, ./Debug/BLib.lib)/* We switch on SWITCH_ID_CD in App, and disable it in BLib.lib */#define SWITCH_ID_CD#include stdio.h#include App.h/* Functions from BLib.lib */extern int get_id_value(ID id);extern int get_ID_E();int main(int argc, char* argv) printf(n- In App -n); printf(ID_E = %d.n, (int)ID_E); / 此处会返回4 printf(n- In BLib.lib -n); printf(ID_E = %d. (call get_ID_E()n, get_ID_E(); / 此处会返回2 getchar(); return 0;App.c 打开了编译开关 SWITCH_ID_CD,所以当App显示ID_E的值时,将会返回4。运行的结果也验证了这一点。- In App -ID_E = 4.- In BLib.lib -ID_E = 2. (call get_ID_E()上面的不匹配就是遇到的问题,怎么解决它呢?曾经考虑过几个方案:方案1:直接Hack出枚举值的数值,然后在BLib.c中使用之方案2:使用字符串到数值的译码方式匹配枚举值方案3:使用extern方式引用外部变量下面分别论述其可行性。方案1:直接Hack出枚举值的数值,然后在BLib.c中使用之这种方法最简单粗暴,既然无法确认App使用了哪些编译开关,那就通过debug的方式将App.h中定义的枚举量的具体数值直接打印出来,然后在BLib.c中使用。但是这种硬编码的方式其扩展性也最差,一旦App的编译开关发生变化,其枚举量势必会跟着变化,这时再手工修改BLib.c就成了苦差事。本方法仅适合于快速调试等短线投资,不适合长线持有。方案2:使用字符串到数值的译码方式匹配枚举值这种方法实现方式就是在BLib.c里新建一个函数,向其传入“ID_E”这个字符串,然后该函数调用App里面的解析函数,将这个字符串匹配到实际的ID_E的数值并返回。听上去稍微优雅一些,但是问题也不少,比方说对于这些字符串的解析过程,将来枚举量增加的话(目前项目的枚举量在上千个左右),还用一堆的if else来线性挨个比较显然效率不高,可如果用HashTable做快速映射则势必增加代码量,更别说存储这些字符串及哈希值需要占用的存储空间了。方案3:使用extern方式引用外部变量考虑再三,要想节省存储空间,又要能够对不同的编译开关产生的枚举值做出适配,用extern方式引用外部变量是个方法,修改代码如下。新增头文件 ForBLib.h 如下:/* Declare and init in App.c, and extern in BLib */#ifdef APP #define GLOBAL#else #define GLOBAL extern#endif/* Declare needed enum, e.g. LIB_ID_E */GLOBAL int LIB_ID_E;当App.c插入此头文件时,宏 GLOBAL 的定义为空,即为声明 LIB_ID_E 变量,而当BLib.c插入此头文件时,宏 GLOBAL 的定义为 extern,即为引用外部变量。BLib.c 修改代码如下:#define BLIB/* App.h is from App, and we have no idea of SWITCH_ID_CD is switched on or off */#include ./App/App.h#include ./App/ForBLib.h/* Get value of id */int get_id_value(ID id) return (int)id;/* It will return 2 because SWITCH_ID_CD not defined in this lib */int get_ID_E() return get_id_value(ID_E);/* It will return 4 if LIB_ID_E is init as ID_E in App.c, or return 0 if not */int get_LIB_ID_E() return get_id_value(LIB_ID_E);在BLib.c中定义了宏 BLIB,用于在插入 ForLibB.h 时识别。App.c 修改代码如下:#define APP/* Link BLib.lib in App */#pragma comment(lib, ./Debug/BLib.lib)/* We switch on SWITCH_ID_CD in App, and disable it in BLib.lib */#define SWITCH_ID_CD#include stdio.h#include App.h#include ForBLib.h/* Functions from BLib.lib */extern int get_id_value(ID id);extern int get_ID_E();extern int get_LIB_ID_E();/* Init LIB_ID_X, e.g. LIB_ID_E = ID_E */void init_LIB_ID() LIB_ID_E = ID_E;int main(int argc, char* argv) printf(n- In App -n); printf(ID_E = %d.n, (int)ID_E); / 此处会返回4 printf(n- In BLib.lib and did not run init_LIB_ID() -n);/ 此时暂未调用 init_LIB_ID() printf(ID_E = %d. (call get_ID_E()n, get_ID_E(); / 此处会返回2 printf(LIB_ID_E = %d. (call get_LIB_ID_E()n, get_LIB_ID_E(); / 此处会返回0,因为 LIB_ID_E 未初始化,被编译器自动初始化为0 printf(n- In BLib.lib and run init_LIB_ID() -n); init_LIB_ID(); / 此时调用 init_LIB_ID(),LIB_ID_E = ID_E printf(ID_E = %d. (call get_ID_E()n, get_ID_E(); / 此处仍然返回2 printf(LIB_ID_E = %d. (call get_LIB_ID_E()n, get_LIB_ID_E(); / 此处会返回4,这就OK了 getchar(); return 0;在App.c中定义了宏 APP,同样用于在插入 ForLibB.h 时识别。运行的结果如下:- In App -ID_E = 4.- In BLib.lib and did not run init_LIB_ID() -ID_E = 2. (call get_ID_E()LIB_ID_E = 0. (call get_LIB_ID_E()- In BLib.lib and run init_LIB_ID() -ID_E = 2. (call get_ID_E()LIB_ID_E = 4. (call get_LIB_ID_E()可见,只要先对变量 LIB_ID_E 进行初始化,则 BLib.c 中使用 LIB_ID_E 就等同于使用 ID_E 了。但是,如果需要用到的枚举量增加,如成百上千个,手工写代码就成了一件苦事,能否通过宏来设计一套机制,只需要更改一处,两边都可以达到升级的目的?3.1 利用宏+extern,一次修改,两边运行增加一个辅助头文件BLibHelper.h如下:#ifndef FORBLIB_H#define FORBLIB_H/* Declared when use in App.c */#ifdef APP #define GLOBAL #else #define GLOBAL extern#endif/* ID_E - LIB_ID_E */#define GET_LIB_ID(ID_NAME) LIB_#ID_NAME/* ID_E - extern int LIB_ID_E */#define DECLARE_LIB_ID(ID_NAME) GLOBAL int GET_LIB_ID(ID_NAME)/* ID_E - LIB_ID_E = (int)ID_E */#define INIT_LIB_ID(ID_NAME) GET_LIB_ID(ID_NAME) = (int)ID_NAME/* Declare and init in App.c */#include ForBLib.h#endifGLOBAL的用法上面已经说过,GET_LIB_ID的用法需要讲讲。举例来说,代码中的 GET_LIB_ID(ID_E) 会被编译器在预编译阶段展开为 LIB_ID_E,宏代码中的#等同于连接左右两端的字符串。同理,代码中的DECLARE_LIB_ID(GET_LIB_ID(ID_E) 会被展开为两个不同的形式,当在App.c中使用时,展开为 int LIB_ID_E,而在BLib.c中使用时,则为 externint LIB_ID_E同理,代码中的INIT_LIB_ID(GET_LIB_ID(ID_E) 会被展开为 LIB_ID_E = (int)ID_E在这个头文件的最后,插入了 ForBLib.h 文件,这个文件与之前的文件变化很大,如下:/* Declare and init in App.c, and extern in BLib */#ifdef APP#define OPERATE_LIB_ID INIT_LIB_ID#else#define OPERATE_LIB_ID DECLARE_LIB_ID#endif/* Declare needed enum, e.g. LIB_ID_E */OPERATE_LIB_ID(ID_E);OPERATE_LIB_ID(ID_F);该文件引用了两个枚举量ID_E和ID_F。如果该文件被App.c插入,其展开就是对下面出现的枚举量初始化,而如果被BLib.c插入,就成了对它们的声明。现在BLib.c的文件修改如下:#define BLIB/* App.h is from App, and we have no idea of SWITCH_ID_CD is switched on or off */#include ./App/App.h#include ./App/BLibHelper.h/* Get value of id */int get_id_value(ID id) return (int)id;/* It will return 2 because SWITCH_ID_CD not defined in this lib */int get_ID_E() return get_id_value(ID_E);/* It will return 4 if LIB_ID_E is init as ID_E in App.c, or return 0 if not */int get_LIB_ID_E() return get_id_value(GET_LIB_ID(ID_E);/* It will return 5 if LIB_ID_F is init as ID_F in App.c, or return 0 if not */int get_LIB_ID_F() return get_id_value(GET_LIB_ID(ID_F);可以看到,它只需要插入BLibHelper.h即可。在BLib.c中,需要使用到ID_E正确的值,只需要调用 GET_LIB_ID(ID_E) 即可,因为这只是一个预编译阶段的宏展开,所以比方案2中的查表匹配效率高。App.c的代码修改为:#define APP/* Link BLib.lib in App */#pragma comment(lib, ./Debug/BLib.lib)/* We switch on SWITCH_ID_CD in App, and disable it in BLib.lib */#define SWITCH_ID_CD#include stdio.h#include App.h#include BLibHelper.h/* Functions from BLib.lib */extern int get_id_value(ID id);extern int get_ID_E();extern int get_LIB_ID_E();/* Init LIB_ID_X, e.g. LIB_ID_E = ID_E */void init_LIB_ID() #include ForBLib.h / 初始化变量int main(int argc, char* argv) printf(n- In App -n); printf(ID_E = %d.n, (int)ID_E); / 此处会返回4 printf(n- In BLib.lib and did not run init_LIB_ID() -n);/ 此时暂未调用 init_LIB_ID() printf(ID_E = %d. (call get_ID_E()n, get_ID_E(); / 此处会返回2 printf(LIB_ID_E = %d. (call get_LIB_ID_E()n, get_LIB_ID_E(); / 此处会返回0,因为 LIB_ID_E 未初始化,被编译器自动初始化为0 printf(n- In BLib.lib and run init_LIB_ID() -n); init_LIB_ID(); / 此时调用 init_LIB_ID(),LIB_ID_E = ID_E printf(ID_E = %d. (call get_ID_E()n, get_ID_E(); / 此处仍然返回2 printf(LIB_ID_E = %d. (call get_LIB_ID_E()n, get_LIB_ID_E(); / 此处会返回4,这就OK了 printf(LIB_ID_F = %d. (call get_LIB_ID_F()n, get_LIB_ID_F(); / 此处会返回5,这就OK了 getchar(); return 0;文件中 init_LIB_ID() 的内容很简单,就是插入 ForBLib.h。运行结果如下:- In App -ID_E = 4.- In BLib.lib and did not run init_LIB_ID() -ID_E = 2. (c
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 轮胎轮辋匹配性能评价
- 混凝土模具工协作考核试卷及答案
- 售后效率改进分析报告
- 音像市场细分策略优化路径分析报告
- 打击乐器制作工质量管控考核试卷及答案
- 碳酸锂转化工技术考核试卷及答案
- 煤直接液化操作工内部技能考核试卷及答案
- 氯乙烯装置操作工专业技能考核试卷及答案
- 液体二氧化碳生产工技能比武考核试卷及答案
- 栓剂工三级安全教育(车间级)考核试卷及答案
- 国家职业技能标准 (2021年版) 燃气供应服务员
- 食品生物技术导论ppt课件
- 非油气探矿权变更延续申请登记书
- 鱼塘补偿协议书范文
- 蓝花花钢琴谱
- 印度白内障小切口手术学习笔记
- 卢春房副部长讲话《树立质量意识,强化风险控制,持续纵深推进铁
- 成型周期公式及计算
- 第11章分析化学中的分离与富集方法
- 管桩垂直度检测报告
- FMEA培训资料(PPT 57页)
评论
0/150
提交评论