因为 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
虽然如此,用 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) 这是一个性能要求相当高基本图像位传送函数,同时又有许多种位操作:
(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"
}