使用 C 语言的“准元程序”设计

将 C 语言的预编译语言看成是“元语言”,使用该元语言进行程序设计

但为什么叫“准元程序”?

因为 C 语言的预编译语言没有迭代结构,所以C 语言的元程序语言不是图灵完备的。举个简单的例子,我们无法用 C 语言的“元语言”写出一个计算 factorial(x)——x 的阶乘的程序;而用 C++的模板就可以(使用模板特化)。因为这需要语言的迭代结构。C预编译语言没有迭代结构的原因是宏替换仅发生在源语言的宏调用中,预编译中的宏调用是不会发生替换的(除了条件编译中条件中对宏的调用)如:

#define  macro1(x)   (x)*(x)
#define  macro2(x)  macro1(x)  // 这里不会发生宏替换
int y = macro2(100);  // 宏替换仅发生在这里
但是,在条件编译中:
#if  macro2(100) == 10000 // 这里会发生宏替换
….
#endif
因此,象这样的程序是错误的:
// fac.c, 计算 x 的阶乘
#if x <= 0
#   define  result  1
#else
 
#   undef  temp_x
#   define temp_x  (x - 1)
#   undef  x
#   define x temp_x
#   include "fac.c"
 
#   undef  temp_result
#   define temp_result result * x
#   undef  result
#   define result  temp_result
 
#endif

适应它,Play With Preprocessor

虽然如此,用 C 语言的预编译能力,在很多时候还是可以写出很好的程序,可以尽可能地减少代码冗余,增强程序性能。程序的可读性,也许增加了,也许减少了;但是在这个探索的过程中,很可能对问题的认识更深刻了,问题得到了更高程度的抽象。

元程序使用的几个重要重要指令:

#define  macro // 用来定义“模板参数”
#undef   macro // 用来清除“模板参数”
#include "template_body" // 用来定义“模板体”
// 符号展开连接:
#define  CAT_TOKEN_1(t1, t2)  t1##t2
#define  CAT_TOKEN(t1, t2)  CAT_TOKEN_1(t1,t2)
// CAT_TOKEN_1 直接将 t1 和 t2 连接成 t1t2,而
// CAT_TOKEN 将 t1 和 t2 展开后再连接,如:
#define  t1  I_am_
#define  t2  lei_peng
CAT_TOKEN_1(t1, t2) // 结果是  t1t2
CAT_TOKEN(t1, t2)   // 结果是  I_am_leipeng

CAT_TOKEN是一个核心的基本构造块。

总体上讲,C++的元程序设计是函数式语言(类似 lisp),而C语言的元程序设计有点类似汇编语言,试看:
// C 元程序代码
#define  param1 ….. 
#define  param2 …..
#define  param3 …..
#include  “template.c”
#undef  param1  // 这些 #undef 也可以位于 “template.c”之内
#undef  param2
#undef  param3

 
// 汇编的函数调用代码
Push  param1
Push  param2
Push  param3
Call function
Add esp, 3 * 4  //恢复堆栈,堆栈也可以在 function 的返回语句恢复

实例,实现函数

int bitblt( GdiDevice* dst, const GdiDevice* src
          , int dx, int dy, int cx, int cy, int sx, int sy
          , BinaryOpCode op
          );
      a)  这是一个性能要求相当高基本图像位传送函数,同时又有许多种位操作:
          (1)  not,and,or,xor,…完备的布尔代数,共16种布尔操作,去掉全真和全假,是14种操作
          (2)  许多种象素位数(1,2,4,8,16,24,32),甚至更多。
          (3)  这些情况组合起来,共有 686种(7×7×14)这显然是一个“过于完备”)的集合。
          (4)  如果按普通的方式编码,要写 686多个不同的函数,或者 switch…case中686种不同的 case。而这些代码都是非常相似的,如果把相同部分提取出来,把不同部分使用“模板”替换掉…..

          (5)  详细内容见代码,代码是非常短的(同时还有另外一个函数mergeblt,原型与bitblt相同,其中仅实现了16,24,32位象素),这些代码如果使用预编译器输出处理结果,有 6000 多行!: 

代码(附件中有完整代码)

// 模板体,bitblt_body.c
//////////////////////////////////////////////////////////////////////////

MCASE(dstBits, srcBits, bitOpCode) {
	callerVars()
	int dstRowBytes = ROW_BYTES_2(dstBits, dst);
	int srcRowBytes = ROW_BYTES_2(srcBits, src);
	int i;
	PBYTE dstRow = dst->data + dy * dstRowBytes + PIX_POS_2(dstBits, dx);
	PBYTE srcRow = src->data + sy * srcRowBytes + PIX_POS_2(srcBits, sx);
	for (i = cy; i; --i) {
		PBYTE dstCol = dstRow;
		PBYTE srcCol = srcRow;
		int j;
		for (j = cx; j; --j) {
			condition(dstCol, srcCol)
				callBitOp(dstCol, srcCol);
		}
		dstRow += dstRowBytes;
		srcRow += srcRowBytes;
	}
}
return 0;

#undef bitOpCode
#undef doBitOp


// 相同象素位的不同位操作(14种)

#define bitOpCode    opCopy
#define doBitOp(d, s)      d = s
#include "bitblt_body.c"

#define bitOpCode    opAnd
#define doBitOp(d, s)      d &= s
#include "bitblt_body.c"

#define bitOpCode    opOr
#define doBitOp(d, s)      d |= s
#include "bitblt_body.c"

#define bitOpCode    opXor
#define doBitOp(d, s)      d ^= s
#include "bitblt_body.c"

#define bitOpCode    opNotSrc
#define doBitOp(d, s)      d = ~s
#include "bitblt_body.c"

#define bitOpCode    opNotAnd
#define doBitOp(d, s)      d = ~(d & s)
#include "bitblt_body.c"

#define bitOpCode    opNotOr
#define doBitOp(d, s)      d = ~(d | s)
#include "bitblt_body.c"

#define bitOpCode    opNotXor
#define doBitOp(d, s)      d = ~(d ^ s)
#include "bitblt_body.c"

#define bitOpCode    opNotDestAnd
#define doBitOp(d, s)      d = ~d & s
#include "bitblt_body.c"

#define bitOpCode    opNotDestOr
#define doBitOp(d, s)      d = ~d | s
#include "bitblt_body.c"

#define bitOpCode    opNotDestXor
#define doBitOp(d, s)      d = ~d ^ s
#include "bitblt_body.c"

#define bitOpCode    opNotSrcAnd
#define doBitOp(d, s)      d &= ~s
#include "bitblt_body.c"

#define bitOpCode    opNotSrcOr
#define doBitOp(d, s)      d |= ~s
#include "bitblt_body.c"

#define bitOpCode    opNotSrcXor
#define doBitOp(d, s)      d ^= ~s
#include "bitblt_body.c"

#undef callBitOp
#undef dstBits
#undef srcBits
#undef pSrcToColor


// blt_body.c, 所有象素位数的模板,这里只定义了 16,24,32三种象素的相互操作

// dst --- 16
#define dstBits  16
#define srcBits  16
#define pSrcToColor  PCOLOR16_TO_32
#define callBitOp(pd, ps)  doBitOp(*(UINT16*)pd,*(UINT16*)ps), pd+=2,ps+=2
#include "bitblt_op.c"

#define dstBits  16
#define srcBits  24
#define pSrcToColor  PCOLOR24_TO_32
#define callBitOp(pd, ps) doBitOp(*(UINT16*)pd, PCOLOR24_TO_16(ps)), \
pd +=2, ps += 3
#include "bitblt_op.c"

#define dstBits  16
#define srcBits  32
#define pSrcToColor(x)  *(x)
#define callBitOp(pd, ps) doBitOp(*(UINT16*)pd, PCOLOR32_TO_16(ps)), \
pd +=2, ps += 4
#include "bitblt_op.c"

// dst --- 24
#define dstBits  24
#define srcBits  16
#define pSrcToColor  PCOLOR16_TO_32
#define callBitOp(pd, ps) doBitOp(pd[0], C16_R(*(UINT16*)ps)), \
doBitOp(pd[1], C16_G(*(UINT16*)ps)), \
	doBitOp(pd[2], C16_B(*(UINT16*)ps)), \
	pd +=3, ps += 2
#include "bitblt_op.c"

#define dstBits  24
#define srcBits  24
#define pSrcToColor  PCOLOR24_TO_32
#define callBitOp(pd, ps) doBitOp(pd[0], ps[0]), \
	doBitOp(pd[1], ps[1]), \
	doBitOp(pd[2], ps[2]),  pd +=3, ps += 3
#include "bitblt_op.c"

#define dstBits  24
#define srcBits  32
#define pSrcToColor(x)  *(x)
#define callBitOp(pd, ps) doBitOp(pd[0], C32_R(*ps)), \
	doBitOp(pd[1], C32_G(*ps)), \
	doBitOp(pd[2], C32_B(*ps)), pd +=3, ps += 4
#include "bitblt_op.c"

	// dst --- 32
#define dstBits  32
#define srcBits  16
#define pSrcToColor  PCOLOR16_TO_32
#define callBitOp(pd, ps)  doBitOp(*(UINT32*)pd, PCOLOR16_TO_32(ps)), \
	pd +=4, ps += 2
#include "bitblt_op.c"

#define dstBits  32
#define srcBits  24
#define pSrcToColor  PCOLOR24_TO_32
#define callBitOp(pd, ps) doBitOp(*(UINT32*)pd, PCOLOR24_TO_32(ps)), \
	pd +=4, ps += 3
#include "bitblt_op.c"

#define dstBits  32
#define srcBits  32
#define pSrcToColor(x)  *(x)
#define callBitOp(pd, ps)  doBitOp(*(UINT32*)pd,*(UINT32*)ps), pd+=4, ps+=4
#include "bitblt_op.c"


	// 函数体,适用于 bitblt 和 mergeblt,模板参数为 condition

	static const unsigned char jump_table[] = {
		0,    bit_1,       bit_2, 0, bit_4 , 0, 0, 0,
		bit_8 ,        0,           0, 0, bit_12, 0, 0, 0,
		bit_16,              0,           0, 0,        0, 0, 0, 0,
		bit_24,        0,     0, 0,        0, 0, 0, 0,
		bit_32
	};
	int jump_index;

	if (dst->colorBits > 32) return -1;
	if (src->colorBits > 32) return -2;
	if ((unsigned int)op >= (unsigned int)BinaryOpCode_Radix)
		return -4;

	jump_index =
		jump_table[dst->colorBits] +
		jump_table[src->colorBits] * bitRadix +  op * bitRadix*bitRadix;

	switch (jump_index)
	{
	default:
		if (0 == jump_table[dst->colorBits])
			return -1; // dst->colorBits error
		else if (0 == jump_table[src->colorBits])
			return -2; // src->colorBits error
		else
			return -3; // not support
#include "blt_body.c"
	}

	return -5; // it will not goes here

#undef  condition



// gdi.h 定义图像基本类型和常量,及 utilities

#ifndef __GDI_H__
#define __GDI_H__

typedef enum BinaryOpCode
{
	opCopy,              // dst = src
	opXor,        // dst = src ^ dst
	opAnd,        // dst = src & dst
	opOr,         // dst = src | dst

	opNotSrc,     // dst = ~src
	opNotAnd,     // dst = ~(src & dst)
	opNotOr,      // dst = ~(src | dst)
	opNotXor,     // dst = ~(src ^ dst)

	opNotDestAnd, // dst = ~dst &  src
	opNotDestOr,  // dst = ~dst |  src
	opNotDestXor, // dst = ~dst ^  src
	opNotSrcAnd,  // dst =  dst & ~src
	opNotSrcOr,          // dst =  dst | ~src
	opNotSrcXor,  // dst =  dst ^ ~src

	//     opSet,        // dst = 1
	//     opClear,      // dst = 0

	BinaryOpCode_Radix
} BinaryOpCode;

typedef unsigned char BYTE, *PBYTE;
typedef unsigned long COLOR;
typedef unsigned short UINT16;
typedef unsigned long  UINT32;

typedef struct _GdiDevice
{
	unsigned int colorBits;
	int           width;
	int           height;
	COLOR  transparentColor;
	int           transparentTolerance;
	COLOR* pallete;
	PBYTE  data;
} GdiDevice;

#define ROW_BYTES_2(colorBits, gdi) ((7 + (gdi)->width * colorBits) >> 3)
#define PIX_POS_2(colorBits, x) ((x * colorBits) >> 3)

#define ROW_BYTES(gdi) ((7 + (gdi)->width * (gdi)->colorBits) >> 3)
#define PIX_POS(gdi, x) ((x * (gdi)->colorBits) >> 3)

#endif


// bitblt.c
// bitblt 函数和 mergeblt的函数体

#include "gdi.h"

enum ColorBitKind
{
	bitError = 0,
	bit_1 = 1,
	bit_2 = 2,
	bit_4,
	bit_8,
	bit_12,
	bit_16,
	bit_24,
	bit_32,
	bitRadix
};

#define CAT_TOKEN1(t1, t2)  t1##t2
#define CAT_TOKEN(t1, t2)   CAT_TOKEN1(t1, t2)

#define MCASE(dstBits, srcBits, bitOpCode)      \
   case CAT_TOKEN(bit_, dstBits) + \
        CAT_TOKEN(bit_, srcBits)*bitRadix + bitOpCode*bitRadix*bitRadix:


// 00RR-RRRR-RRRR-GGGG-GGGG-GGBB-BBBB-BBBB
// 0x3FF00000  0x000FFC00  0x000003FF
#define C32_R(c)     (c >> 20 & 0x3FF)
#define C32_G(c)     (c >> 10 & 0x3FF)
#define C32_B(c)     (c     & 0x3FF)

#define C16_R(c)     (c >> 10 & 0x1F)
#define C16_G(c)     (c >>  5 & 0x1F)
#define C16_B(c)     (c     & 0x1F)

#define PCOLOR24_TO_16(p24)  (\
		((UINT16)p24[2]&0xF8) << 8 |\
		((UINT16)p24[1]&0xF8) << 3 |\
				 p24[0]       >> 3)
// 这几种颜色转换未实现
#define PCOLOR32_TO_16(p32)  0

#define PCOLOR16_TO_24(p16)  0
#define PCOLOR32_TO_24(p16)  0

#define PCOLOR16_TO_32(p24)  0
#define PCOLOR24_TO_32(p24)  0

// empty...
#define callerVars()

int bitblt(GdiDevice* dst, const GdiDevice* src,
		int dx, int dy, int cx, int cy, int sx, int sy, BinaryOpCode op)
{
#define condition(pd, ps)
#include "template/fun_body.c"
}

int mergeblt(GdiDevice* dst, const GdiDevice* src,
		int dx, int dy, int cx, int cy, int sx, int sy, BinaryOpCode op)
{
	// condition no tolerance...
#define condition(pd, ps)  if (pSrcToColor(ps) != src->transparentColor)
#include "template/fun_body.c"
}




你可能感兴趣的:(C++)