现在的位置: 首页 > 综合 > 正文

gsl中的代码重用技术

2013年10月23日 ⁄ 综合 ⁄ 共 3163字 ⁄ 字号 评论关闭

http://blog.csdn.net/insectC/article/details/5310991

     在gsl中,由于有float、double、long double多种数据精度,因此如果针对每一种数据精度都分别实现诸如内存分配等函数,代码量将骤增数倍。因此各种数据类型共用这些代码就显得相当重要。gsl利用c语言的预编译命令实现了这种代码的重用功能。

      这里我们以最为基础的gsl_block_alloc函数模板为例,剖析gsl代码重用的原理。

     下面给出该函数的模板源代码

    

  1. 【block/init_souce.c】  
  2. ......  
  3. TYPE (gsl_block) *  
  4. FUNCTION (gsl_block, alloc) (const size_t n)  
  5. {  
  6.   TYPE (gsl_block) * b;  
  7.   ......  
  8.   b = (TYPE (gsl_block) *) malloc (sizeof (TYPE (gsl_block)));  
  9.   ......  
  10.   b->data = (ATOMIC *) malloc (MULTIPLICITY * n * sizeof (ATOMIC));  
  11.   ......  
  12.   b->size = n;  
  13.   return b;  
  14. }  

 

    在《gsl数据类型之向量http://blog.csdn.net/insectC/archive/2010/01/27/5262444.aspx》一文中,我们指出对于double精度,函数中宏的值为:

  1. 【templates_on.h】  
  2. ......  
  3. #define ATOMIC double  
  4. #define MULTIPLICITY 1  
  5. ......  
  6. #define CONCAT2x(a,b) a ## _ ## b   
  7. #define CONCAT2(a,b) CONCAT2x(a,b)  
  8. ......  
  9. #define FUNCTION(dir,name) CONCAT2(dir,name)  
  10. #define TYPE(dir) dir  
  11. ......  

 

      编译后将得到gsl_block_alloc函数,其作用是创建一个包含n个double精度数据的数据块。

      而实际上,这一函数模板同样也可以编译成gsl_block_float_alloc,gsl_block_long_double_alloc等等,分别用于创建float精度与long double精度的向量。

      其中的奥秘就在block/init_source.c与templates_on.h、templates_off.h的互相配合中。让我们来看看block/init.c文件的代码:

 

  1. 【block/init.c】  
  2. #include <config.h>  
  3. #include <stdlib.h>  
  4. #include <gsl/gsl_block.h>  
  5. ......  
  6. #define BASE_DOUBLE  
  7. #include "templates_on.h"  
  8. #include "init_source.c"  
  9. #include "templates_off.h"  
  10. #undef  BASE_DOUBLE  
  11. #define BASE_FLOAT  
  12. #include "templates_on.h"  
  13. #include "init_source.c"  
  14. #include "templates_off.h"  
  15. #undef  BASE_FLOAT  
  16. ......  

 

      限于篇幅,其中略去了除float,double外的其他精度类型的代码。

      让我们来跟踪编译过程。首先在定义了BASE_DOUBLE后,编译器将引入templates_on.h。头文件中的关键内容如下:

  1. 【templates_on.h】  
  2. #if defined(BASE_GSL_COMPLEX_LONG)  
  3. ......  
  4. #elif defined(BASE_DOUBLE)  
  5. #define BASE double  
  6. #define SHORT  
  7. #define ATOMIC double  
  8. #define MULTIPLICITY 1  
  9. #define FP 1  
  10. #define IN_FORMAT "%lg"  
  11. #define OUT_FORMAT "%g"  
  12. #define ATOMIC_IO ATOMIC  
  13. #define ZERO 0.0  
  14. #define ONE 1.0  
  15. #define BASE_EPSILON GSL_DBL_EPSILON  
  16. #elif defined(BASE_FLOAT)  
  17. #define BASE float  
  18. #define SHORT float  
  19. #define ATOMIC float  
  20. #define MULTIPLICITY 1  
  21. #define FP 1  
  22. #define IN_FORMAT "%g"  
  23. #define OUT_FORMAT "%g"  
  24. #define ATOMIC_IO ATOMIC  
  25. #define ZERO 0.0F  
  26. #define ONE 1.0F  
  27. #define BASE_EPSILON GSL_FLT_EPSILON  
  28. ......  
  29. #endif  

 

在文件中,ATOMIC被定义为 double,MULTIPLICITY被定义为1。这与前文一致。随后我们又将进一步定义一系列的宏:

  1. 【templates_on.h】  
  2. ......  
  3. #define CONCAT2x(a,b) a ## _ ## b   
  4. #define CONCAT2(a,b) CONCAT2x(a,b)  
  5. #define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c  
  6. #define CONCAT3(a,b,c) CONCAT3x(a,b,c)  
  7. #define CONCAT4x(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d  
  8. #define CONCAT4(a,b,c,d) CONCAT4x(a,b,c,d)  
  9. ......  
  10. #if defined(BASE_DOUBLE)  
  11. #define FUNCTION(dir,name) CONCAT2(dir,name)  
  12. #define TYPE(dir) dir  
  13. #define VIEW(dir,name) CONCAT2(dir,name)  
  14. #define QUALIFIED_TYPE(dir) TYPE(dir)  
  15. #define QUALIFIED_VIEW(dir,name) CONCAT2(dir,name)  
  16. #else  
  17. #define FUNCTION(a,c) CONCAT3(a,SHORT,c)  
  18. #define TYPE(dir) CONCAT2(dir,SHORT)  
  19. #define VIEW(dir,name) CONCAT3(dir,SHORT,name)  
  20. #define QUALIFIED_TYPE(dir) TYPE(dir)  
  21. #define QUALIFIED_VIEW(dir,name) CONCAT3(dir,SHORT,name)  

抱歉!评论已关闭.