近日移植TightVNC,关于RectangleUpdate的编码,处理不同色彩位深bits/pixe( 8,16,32)有着极其相似的处理方法,由于C中没有模板函数的概念,因而采用了宏定义来处理,与模板函数有着异曲同工之妙。现摘录分析如下(代码有删节):
Rfbproto.c文件中
/* CONCAT2 concatenates its two arguments.
CONCAT2E does the same but also expands its arguments if they are macros
注解:CONCAT2(a,b)直接将两字符串连接成新的字符串。而CONCAT2E(a,b),如果a和b被其它的宏定义了话,则会对a和b进行解释替换后,再合成新的字符串。*/
#define CONCAT2(a,b) a##b
#define CONCAT2E(a,b) CONCAT2(a,b)
#define BPP 8
#include “rre.c”
#undef BPP
#define BPP 16
#include “rre.c”
#undef BPP
#define BPP 32
#include “rre.c”
#undef BPP
“rre.c”文件如下:
#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
#define CARDBPP CONCAT2E(CARD,BPP)
static bool HandleRREBPP (int rx, int ry, int rw, int rh)
{…}
这样在使用者文件rfbproto.c中,为BPP定义了三个值,做了三次包含。每次包含的过程:
所定义的函数HandleRREBPP被替换成CONCAT2E(HandleRRE, BPP),进而再次被替换成CONCAT2E(HandleRRE, [8,16,32]),然后经由CONCAT2(HandleRRE, [8,16,32])替换成HandleRRE[8,16,32],于是就有了HandleRRE8, HandleRRE16, HandleRRE32。
其整个过程是,通过三次包含,将HandleRREBPP替换为HandleRRE8, HandleRRE16和HandleRRE32。其方法核心是先将HandleRREBPP都替换为CONCAT2E(HandleRRE,BPP),通过引入不同的BPP值,然后再合并。
其效果类似于C++中的函数模板。C++模板由编译器根据不同模板实参生成具体的实例函数,而此处则是通过指定宏的值,然后手工三次包含,利用预编译,完成替换。
可见,再次印证了C跟C++比,并不缺某些机制。换句话说,C++的特有机制,用C也可以变通实现,就像C++的面向对象和动态联编,在C中也可以类似实现,只不过需要手工去做,有些繁琐罢了;而C++中,则由编译器替你做好了,不需程序员去做这些琐碎工作。