本站动态:

inline的一种特殊用法

曾经我在一个c文件里用几个函数实现了一个比较Common的Functions,并提供一个对应的h文件让使用者#include。接口如下:

//please do not call these functions directly
int WriteTrace(int nLevel, char* pFile, int nLine, char* format, ...);
void EndWriteTrace(void);

这个Common的功能会在很多地方被人调用,但是它只在target端(真实运行环境)运行,而在simulator端(模拟运行环境,为方便调试加快编程速度而引入的模拟的运行环境)不需要/无法运行该功能。所以我定义了下面一些宏,让用户通过宏来调用这些提供出来的接口:

//please use these macros instead
#ifdef AEE_SIMULATOR //don't let it run in simulator
    #define TRACE_FILE
    #define END_TRACE
#else
    #define TRACE_FILE WriteTrace
    #define END_TRACE  EndWriteTrace
#endif

为了方便描述问题,模拟地写了一段代码:

 

  1. int WriteTrace(int nLevel, int add)
  2. {
  3.     return nLevel + add;
  4. }
  5. void EndWriteTrace(void)
  6. {
  7.     return;
  8. }
  9. //#define AEE_SIMULATOR
  10. #ifdef AEE_SIMULATOR //don't let it run in simulator
  11.     #define TRACE_FILE
  12.     #define END_TRACE
  13. #else
  14.     #define TRACE_FILE WriteTrace
  15.     #define END_TRACE  EndWriteTrace
  16. #endif
  17.  
  18. int main(void)
  19. {
  20.     TRACE_FILE(1, 3);
  21.     END_TRACE();
  22.     return 0;
  23. } 


当AEE_SIMULATOR未被定义时,那么TRACE_FILE就是WriteTrace,END_TRACE就是EndWriteTrace,也就是前文提到的在target端运行,这样不存在任何问题,可以无错误无警告通过编译。但是如果定义了AEE_SIMULATOR,也就是想编译出在simulator上运行的代码,会发现会有一个错误。错误原因很容易发现,因为main函数体内第二行语句END_TRACE();宏展开后的代码是();,这句代码自然不可以编译通过了。那第一行TRACE_FILE(1, 3);宏展开后是(1, 3);为什么没有错误也没有警告呢?因为(1, 3);是C语言中的表达式(逗号运算,表达式的值是3),就算是(1); 也是C语言中的表达式(表达式的值是1),没有错误。因为(void);不是表达式(void不是值),所以就算将END_TRACE()改成END_TRACE(void)也是不能通过编译的。

要解决这样的问题,我最先想到了两种解决方案:

1、给END_TRACE添加一个无效的参数。对于target端,多了一个无效参数,有一定的资源浪费,不过影响小到可以忽略。

2、在simulator上实现一个空函数void funNum(void),将END_TRACE定义为该函数的函数名funNum,这样做对target端无任何影响,但是simulator端多了一个空函数,加大了编译出来的文件,不过影响同样很小。关键是要添加空函数void funNum(void)的实现,当然最适合放在我提供的那个c文件里。不过这样需要增加工作量,在simulator的编译工程中也需要将该c文件编译进来,需要修改到dsp文件,而实际上我们不希望这样(在simulator上只需要包含h文件即可编译通过了,那c文件不需要编译,也不需要加到工程中)。

后来想到了一个完美的方法,既解决了问题,又没有上面的问题。那就是在h文件中实现空函数void funNum(void),不过得加关键字__inline

 

  1. //-------------in .c file------------------------//
  2. int WriteTrace(int nLevel, int add) 
  3. { 
  4.     return nLevel + add; 
  5. } 
  6. void EndWriteTrace(void) 
  7. { 
  8.     return; 
  9. }
  10.  
  11. //---------in .h file that for users to include------//
  12. __inline void FuncName(void)
  13. {
  14.     //this function's just empty for special usage
  15. }
  16. //#define AEE_SIMULATOR 
  17. #ifdef AEE_SIMULATOR //don't let it run in simulator 
  18.     #define TRACE_FILE 
  19.     #define END_TRACE FuncName
  20. #else 
  21.     #define TRACE_FILE WriteTrace 
  22.     #define END_TRACE  EndWriteTrace 
  23. #endif 
  24.  
  25. //------------in test.c file------------//
  26. int main(void) 
  27. { 
  28.     TRACE_FILE(1, 3); 
  29.     END_TRACE(); 
  30.     return 0; 
  31. }  

 



[本日志由 shosh 于 2009-02-24 04:05 PM 编辑]
文章来自: Shosh原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
相关日志:
评论: 3 | 引用: 0 | 查看次数: 1024
回复回复shosh[2010-04-29 02:31 PM | del]
当初失误了,其实对于END_TRACE的定义可以这样来做的:
#ifdef AEE_SIMULATOR
#define END_TRACE()
#else
#define END_TRACE EndWriteTrace
#endif

这样不管什么用的是什么,都可以调用END_TRACE();了。
这里的EndWriteTrace省略了函数体中的代码,并不是空函数。
回复回复clybe[2009-03-03 11:30 PM | del]
呵呵 为这个煞费苦心啊~
评论由Shosh回复于2009-03-04 05:05 PM Shosh回复[2009-03-04 05:05 PM]
呵呵,为写而写。本来早该写的,因为这是好几个星期前做的事情,结果因为懒惰,才拖到最近。
回复回复shosh[2009-02-25 04:24 PM | del]
引用内容 引用内容
所以就算将END_TRACE()改成END_TRACE(void)也是不能通过编译的。

这句话有些不妥,因为即使是直接的函数调用,若函数的参数为void,调用时是不能够在括号里加行void的。
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭