程序App链接B库时如何解决枚举值不匹配

上传人:仙*** 文档编号:127270532 上传时间:2022-07-29 格式:DOC 页数:12 大小:123.50KB
收藏 版权申诉 举报 下载
程序App链接B库时如何解决枚举值不匹配_第1页
第1页 / 共12页
程序App链接B库时如何解决枚举值不匹配_第2页
第2页 / 共12页
程序App链接B库时如何解决枚举值不匹配_第3页
第3页 / 共12页
资源描述:

《程序App链接B库时如何解决枚举值不匹配》由会员分享,可在线阅读,更多相关《程序App链接B库时如何解决枚举值不匹配(12页珍藏版)》请在装配图网上搜索。

1、情况是这样的: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_C

2、D 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 swi

3、tched 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.l

4、ib 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);

5、 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()上面的不匹配就是遇到的问题,怎么解决它呢?曾经考虑过几个方案:

6、方案1:直接Hack出枚举值的数值,然后在BLib.c中使用之方案2:使用字符串到数值的译码方式匹配枚举值方案3:使用extern方式引用外部变量下面分别论述其可行性。方案1:直接Hack出枚举值的数值,然后在BLib.c中使用之这种方法最简单粗暴,既然无法确认App使用了哪些编译开关,那就通过debug的方式将App.h中定义的枚举量的具体数值直接打印出来,然后在BLib.c中使用。但是这种硬编码的方式其扩展性也最差,一旦App的编译开关发生变化,其枚举量势必会跟着变化,这时再手工修改BLib.c就成了苦差事。本方法仅适合于快速调试等短线投资,不适合长线持有。方案2:使用字符串到数值的译码方

7、式匹配枚举值这种方法实现方式就是在BLib.c里新建一个函数,向其传入“ID_E”这个字符串,然后该函数调用App里面的解析函数,将这个字符串匹配到实际的ID_E的数值并返回。听上去稍微优雅一些,但是问题也不少,比方说对于这些字符串的解析过程,将来枚举量增加的话(目前项目的枚举量在上千个左右),还用一堆的if else来线性挨个比较显然效率不高,可如果用HashTable做快速映射则势必增加代码量,更别说存储这些字符串及哈希值需要占用的存储空间了。方案3:使用extern方式引用外部变量考虑再三,要想节省存储空间,又要能够对不同的编译开关产生的枚举值做出适配,用extern方式引用外部变量是个

8、方法,修改代码如下。新增头文件 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 修改代

9、码如下:#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_va

10、lue(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,

11、 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,

12、 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 未初始化,

13、被编译器自动初始化为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.

14、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 了。但是,如

15、果需要用到的枚举量增加,如成百上千个,手工写代码就成了一件苦事,能否通过宏来设计一套机制,只需要更改一处,两边都可以达到升级的目的?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

16、/* 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(

17、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

18、, 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 BLI

19、B/* 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);/*

20、 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.

21、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

22、/* 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

23、 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_

24、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。运行结果

25、如下:- 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 = 4. (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_F = 5. (call get_LIB_ID_F()如果需要增加枚举量,只需要修改ForBLib.h 即可,如:.OPERATE_LIB

26、_ID(ID_E);OPERATE_LIB_ID(ID_F);/ 此处增加新枚举量,如/ OPERATE_LIB_ID(ID_G);之所以在定义 LIB_ID_E 时类型为 int 而不是 ID,是因为枚举值可以轻易的转为 int 值,这样在增加不同类型的枚举量时不用考虑类型不一致了。附上方案3.1的VC2010版本例子代码,在这里。需要注意的是App和BLib都是选择“Compile As C Code”综上所述,使用方案3.1还是较为简单粗暴的:- App.c 和 BLib.c 都插入 BLibHelper.h 这个头文件,App.c中加入一个 init_LIB_ID() 的函数,内容只有一句 #include ForBLib.h。- BLib.c 中使用 ID_E 这样的枚举量时,使用GET_LIB_ID(ID_E) 的方式。- 需要增加枚举量X时,就在 ForBLib.h 后面增加OPERATE_LIB_ID(X);题外话,如果要提高App的可移植性,最好还是将App.h中的枚举量如下挨个硬编码出确定数值,这样就不需要担心被编译开关打断了。typedef enum t_ID ID_A = 0, ID_B = 1,#ifdef SWITCH_ID_CD ID_C = 2, ID_D = 3,#endif ID_E = 4, ID_F = 5ID;爱生活,爱拉风

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!