在 C 语言中实现模板函数的方法

主题: 在 C 语言中实现模板函数的方法
作者:  csdn-whinah
发表日期: 2004年06月07日

背景

  本文是我毕业第一份工作期间(2003年),在一个嵌入式平台中实现一个 Fat 文件系统时,针对 Fat12/Fat16/Fat32,有大量的相似代码,但平台只有 C 编译器,无 C++,为了消除代码重复,苦思冥想,最终得出来的方法。本文原文最早于 2004 年发布在 CSDN 上,后来迁移到我的个人网站  nark.cc,现在贴到知乎,与大家分享!

C++ Template

  现以一个求和函数 Sum 为例,用 C++ Template 可写如下:

template<class T, class R>
R Sum(const T *array, int n) {
    R sum = 0;
    for (int i = 0; i < n; ++i) sum += i;
    return sum;
}

  如果不是内置类型,该模板隐式地需要 有 R R::operator+=(T)运算符可用。

三种使用 C 语言模拟C++的模板的方法

1. 使用函数指针作为 Functor 替换者

struct AddClass {
    Void (*add)(char* r1, const char* r2);
    Int elemSize;
    Char  sum[MAX_ELEM_SIZE];
};
void Sum(struct AddClass* self, const char* array, int n) {
     int i;
     for (i = 0; i < n; ++i)
         self->add(self->sum, array + i*self->elemSize);
}
 
// 使用时:
// …..
 
Void AddInt(char* r1, const char* r2) {
    *(long*)r1 += *(int*)r2;
}
AddClass addClass = {AddInt, 2, 0 };
Int array[100];
Read(array);
Sum(&addClass, array, 100);
// …..

2. 用宏作为Functor的替换者

#define GenSumFun(SumFunName, Add, RetType, ElemType) \
RetType SumFunName (const ElemType *array, int n) {   \
    RetType sum = 0; int i;                           \
    for (i = 0 ; i < n ; ++i) Add(sum, i);            \
    return sum;                                       \
}
// 使用时:
#define AddInt(x, y)  ((x) += (y))
GenSumFun(SumInt, AddInt, long, int)
// …..
int array[100];
Read(array);
long sum = SumInt(array, 100);
// …..

3. 所有可替换参数均为宏

至少需要一个额外的文件(实现文件)为 impsum.h

/* impsum.h */
RetType FunName(const ElemType *array, int n) {                                                                     
    RetType sum = 0;
    int i;
    for (i = 0 ; i < n ; ++i) Add(sum, i);                            
    return sum;                                          
}
 
/* 使用时:some-file.c */
#undef  RetType
#undef  FunName
#undef  ElemType
#undef  Add
#define AddInt(x, y)  ((x) += (y))
#define RetType long
#define FunName SumInt
#define ElemType int
#define Add  AddInt

#include impsum.h
 
…..
int array[100];
Read(array);
long sum = SumInt(array, 100);
…..

总结:

  第一种方法,易于跟踪调试,但是效率低下,适用于对可变函数(函数指针)的效率要求不高,但程序出错的可能性较大(复杂),模板函数(Sum)本身很复杂,模板参数也比较复杂(add)的场合。
  第二种方法,效率高,但很难跟踪调试,在模板函数和模板参数本身都很复杂的时候更是如此。
  第三种方法,是我最近几天才想出的,我认为是最好的,在模板参数(Add)比较复杂时可以用函数(第二种也可以如此),简单时可以用宏,并且,易于调试。在模板函数本身很复杂,而模板参数比较简单时更为优越。但是,可能有点繁琐。
  一般情况下,没有必要做如此劳心的工作,一切交给编译器去做就行了。但是本人在开发一个文件系统时,由于是基于一种少见的平台,没有可用的C++编译器,有几个函数,除了其中的类型不同(uint16 和 uint32),和几个可参数化的宏不同,其它地方完全相同,而函数本身很复杂(两百多行代码)。Copy出几个完全类似的函数副本,维护起来特别烦人。非常需要如此的编程模式,故此,分享出来,大家共同探讨。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值