使用" 参数化基类" 和" 成员函数指针" 模拟实现虚函数

阅读更多关于《使用" 参数化基类" 和" 成员函数指针" 模拟实现虚函数》

// 使用" 参数化基类"" 成员函数指针" 模拟实现虚函数。

#include "stdafx.h"

 

/*

    使用 "参数化基类 " "成员函数指针 "模拟实现虚函数。

    可能大家都以为只有疯子才会这么干,好好的虚函数干吗不用,而偏要拐弯抹角地

    搞得这么复杂,但有时候这可能是最好地选择。举个例子吧,我写 Windows PE 文件

    加壳程序的时候,遇到一个问题:

    1. 我开发了一个框架,可以只用 C++ 来写 "壳程序 ",大家很难想到吧!

    2. 但不能使用一些 C++ 功能:虚函数,异常处理,还有 switch-case 语句

    3. C++ 异常处理可以不用,但是不能使用虚函数可能太过苛刻。

 

    当我看了 "generative programming"以后,觉得 "参数化继承 "

    或许可以满足这个需求,模拟实现虚函数。

    以下是使用 "参数化继承 "实现虚函数的框架,以及要注意的事项。

 

    BaseClass 显然,实际上是 "抽象基类 ",因为如果实例化

    "InstantialClass<ConcreteClass>" 时,ConcreteClass

    必须定义响应的 "虚函数 ",否则编译就报错。如果相应的

    BaseClass InstantialClass 定义正确无误(从代码可以

    看到,这很简单,但比较麻烦,必须注意一些细节)。因此

    ConcreteClass 编译期错误不会被推迟到运行时才发现,

    而使用其它方式模拟,就很难有这个保证。

 

    其实,如果了解 C++ 的底层对象模型,这些需要注意的细节

    很容易理解!

 

    //——-

    另外有一种 C 语言模拟 C++ 虚函数的方法,可以在我以前

    (2002 )一篇文章中看到。

*/

class BaseClass

{

#define DEFINE_VIRTUAL(ret , name, param_list, call_list ) /

protected :  /

    typedef ret (BaseClass ::*T## name) param_list ;   /

    T## name p ##name;     /

public :                 /

    ret name param_list /

    { return ( this->*this ->p## name)call_list ; }

 

//////////////////////////////////////////////////////////////////////////

// expansion of :

/*  DEFINE_VIRTUAL(int, Func1,

        (int x1, int x2),

        (   x1,    x2)

        );

*/

protected :

    typedef int (BaseClass ::*TFunc1)( int x1 , int x2);

    TFunc1 pFunc1;

public :

    int Func1(int x1, int x2 )

    {

        return ( this->*this ->pFunc1)( x1, x2 );

    //  return (this->*pFunc1)(x1, x2); // can be simplified as this line.

    }

// end expansion

//////////////////////////////////////////////////////////////////////////

 

    DEFINE_VIRTUAL( int, Func2 ,

        (int x1, int x2, int x3 ),

        (   x1 ,    x2 ,    x3 )

        );

 

protected :

    template< typename AddressType >

    AddressType convert_address(AddressType address)

    {

        // if used in shell code, this must return another valid address.

        return address;

    }

public :

    template< typename BaseFuncType , typename ConcreteFuncType>

    void assign(BaseFuncType & x, ConcreteFuncType y )

    {

    // if use C Style cast like "(BaseFunType)(y)", it is danger!!

    // any member function can be assigned to x!!

    //  x = convert_address((BaseFuncType)(y)); // danger!!

        x = convert_address(static_cast <BaseFuncType>( y));

    }

    BaseClass()

    {

        pFunc1 = 0;

        pFunc2 = 0;

    }

};

 

class ConcreteClass1

{

private :

    int x1, x2 , x3;

public :

    int Func1(int x1, int x2 )

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        std:: cout << "ConcreteClass1::Func1" << "/n" ;

        std:: cout << "x1=" << x1 << ", x2=" << x2 << "/n/n";

        return 0;

    }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        std:: cout << "ConcreteClass1::Func2" << "/n" ;

        std:: cout << "x1=" << x1 << ", x2=" << x2 << ", x3=" << x3 << "/n/n";

        return 0;

    }

};

 

class ConcreteClass2

{

private :

    int x1, x2 , x3;

public :

    int Func1(int x1, int x2 )

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        std:: cout << "ConcreteClass2::Func1" << "/n" ;

        std:: cout << "x1=" << x1 << ", x2=" << x2 << "/n/n";

        return 0;

    }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        std:: cout << "ConcreteClass2::Func2" << "/n" ;

        std:: cout << "x1=" << x1 << ", x2=" << x2 << ", x3=" << x3 << "/n/n";

        return 0;

    }

};

 

template <class ConcreteClass>

class InstantialClass :

    // "BaseClass" must be first base class, otherwise,

    // function pointer convert in "BaseClass::assign()" may be not valid!

    public BaseClass, // interface inherit, multi inherit is not allowed!!

    protected ConcreteClass // implementation inherit, multi inherit is allowed

{

    // it is a guide line that do not hold any data member in this class!!

    //

    // if ‘BaseClass’ is not the first base class for ‘this’ class,

    // and data member is defined here,

    // and these data member will be modified,

    // it will error at runtime!

    // you can reverse the inherit order of

    // BaseClass and ConcreteClass, and try!!

    //

    int x1, x2 , x3;

public :

    // must delegate these member functions…

    int Func1(int x1, int x2 ) { return ConcreteClass::Func1 (x1, x2); }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        return ConcreteClass::Func2 (x1, x2, x3 );

    }

 

    InstantialClass()

    {

    // must assign these member function pointers…

    //  BaseClass::pFunc1 = (TFunc1)(Func1);

        assign( pFunc1, Func1 );

        assign( pFunc2, Func2 );

 

    // if use C Style cast in assign, follow line can be compiled,

    // but will error at runtime, because pointer to ConcreteClass

    // is different from to ‘this’!!

    // pointer to ‘BaseClass’ is equal to ‘this’..

    // so, do not write such code,

    // must delegate ‘ConcreteClass::Func2’ to ‘this->Func2’.

    // assign(pFunc2, ConcreteClass::Func2);

    }

};

 

int _tmain( int argc , _TCHAR* argv[])

{

    BaseClass* p1 = new InstantialClass< ConcreteClass1>();

    BaseClass* p2 = new InstantialClass< ConcreteClass2>();

 

    p1-> Func1(1111 , 2222);

    p2-> Func1(1111 , 2222);

    p1-> Func2(1111 , 2222, 3333);

    p2-> Func2(1111 , 2222, 3333);

 

    p1-> Func1(1111 , 2222);

    p2-> Func1(1111 , 2222);

    p1-> Func2(1111 , 2222, 3333);

    p2-> Func2(1111 , 2222, 3333);

 

    delete p2;

    delete p1;

 

    return 0;

}

 

 

stl::set 的一个缺陷

阅读更多关于《stl::set 的一个缺陷》

stl::set  什么都好,就一点不好:不能仅仅通过 key去查找元素。

例如

 

搞 Java 也有一段时间了

阅读更多关于《搞 Java 也有一段时间了》

搞 Java 也有一段时间了。

Java 现在也支持 GP 了。

但是感觉 Java 好像总是那么那么的。

可能是 C++ 用惯了。

但是 C++ 的表达能力是在是比 Java 强得多。

MS 也推出了 C++/CLI,简单得看了一下,那简直就是我梦想中的 C++ 应该有的样子,虽然看上去有点复杂。

Java 的 GP 语法,虽未如 C++ 般达到了图灵完备,但是它的 F-约束,比起 C++ ,要好一些,它很直观,而实际上在 C++ 中没有相同的语法结构。

C++ 有没有必要也增加这种语法呢?

自适应Lru(最近最少使用)算法

阅读更多关于《自适应Lru(最近最少使用)算法》

在缓存管理算法中,Lru 几乎是公认的最优的算法。然而它也有一些缺陷,主要是因为:它假定对实体的访问有局部特性。当访问模式没有局部特性的时候,它就会退化为FIFO(先进先出)算法。 继续阅读

高性能文件系统实现

阅读更多关于《高性能文件系统实现》
 

高性能文件系统-演示文档

PowerPoint下载

演示文档首页

Word Doc 文档下载

Fat 文件系统规格白皮书
文件系统的两种实现

标题

高性能文件系统 (该页文档描述)

最小实现

可扩展性

优良(基于虚拟文件系统构架)

时间性能

优良,接近硬件极限速度,
可用于驱动硬盘

差,仅可用于驱动存储卡片

空间性能

较大, Rom(Code)30K , Ram(RunTime) >= 32K

Rom(code) < 8KRam(RunTime) >=2K

支持

Fat12/Fat16/Fat32 ,长文件名

Fat12/Fat16 ,仅 8.3 文件名

可自定义路径解析

其它特点

对连续簇编组,不用 FatCache

FatCache

源码下载:

高性能文件系统( PowerPoint 文档描述)

最小实现
一个国外的Fat文件系统 (使用的是 FatCache ,不是对连续簇编组)

这些源码任何人可以自由下载,自由改动,
但我对此不提供技术支持,如果需要支持, 请联系我们!

C++使用模板进行的一种重构

阅读更多关于《C++使用模板进行的一种重构》

如果有一些遗留代码,里面有很多结构,定义了一些相同的成员,但在一些时候,需要取出这些成员,进行同样的处理。如下面这些代码的红色部分。

——原先的程序结构是使用类型码来区分实际的类型,客观地说,这些遗留代码是比较混乱的。

不想说太多,用简单的代码来说明问题吧。

typedef struct   _EVT_SWITCH : public EVT_HEAD {
 DWORD dwCategory;
 DWORD  dwSeverity;
 DWORD dwEvtSrcID;
 DWORD dwEvtSrcOffset;
 DWORD   dwSrcIp;
 DWORD   dwSrcPort;
 DWORD   dwDstIp;
 DWORD   dwDstPort;
 DWORD   dwProtocol;
 DWORD dwEvtUserOffset;
 DWORD   dwEvtUserIp;
 DWORD dwStatus;
 DWORD   dwOp;
 DWORD dwEvtNum;
 DWORD dwDetailOffset;
 CHAR szContent[0];
}EVT_SWITCH,*PEVT_SWITCH;

typedef struct   _EVT_ROUTER : public EVT_HEAD {
 DWORD dwCategory;
 DWORD  dwSeverity;
 DWORD dwEvtSrcID;
 DWORD dwEvtSrcOffset;
 DWORD   dwSrcIp;
 DWORD   dwSrcPort;
 DWORD   dwDstIp;
 DWORD   dwDstPort;
 DWORD   dwProtocol;
 DWORD dwEvtUserOffset;
 DWORD   dwEvtUserIp;
 DWORD dwStatus;
 DWORD   dwOp;
 DWORD dwEvtNum;
 DWORD dwDetailOffset;
 CHAR szContent[0];
}EVT_ROUTER,*PEVT_ROUTER;

typedef struct  _EVT_NETWORK : public EVT_HEAD {
 DWORD dwCategoryOffset;
 DWORD  dwSeverity;
 DWORD dwEvtId;
 DWORD dwEvtSrcOffset;
 DWORD dwEvtUserOffset;
 DWORD dwEvtTypeOffset;
 DWORD dwSrcIp;
 DWORD dwSrcPort;
 DWORD dwDstIp;
 DWORD dwDstPort;
 DWORD dwProtocol;
 DWORD dwSmacOffset;
 DWORD dwDmacOffset;
 DWORD dwFlagOffset;
 DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
 DDWORD ddwSessionId;
 DWORD dwRuleOffset;
 DWORD dwStatusOffset;
 DWORD dwOpOffset;
 DWORD dwReasonOffset;
 int tDuration;
 DWORD dwEvtNum;
 DWORD   dwArgOffset;
 DWORD dwMsgOffset;
 DWORD dwDetailOffset;
 CHAR szContent[0];
}EVT_FW,*PEVT_FW,EVT_NETWORK,*PEVT_NETWORK;

typedef struct  _EVT_VPN : public EVT_HEAD {
 int tDuration;
 DWORD dwCategoryOffset;
 DWORD  dwSeverity;
 DWORD dwEvtId;
 DWORD dwEvtSrcOffset;
 DWORD dwEvtUserOffset;
 DWORD dwEvtTypeOffset;
 DWORD   dwDevActionOffset;
 DWORD dwDevMoudleNameOffset;
 DWORD dwServiceOffset;
 DWORD dwSrcIp;
 DWORD dwSrcPort;
 DWORD dwDstIp;
 DWORD dwDstPort;
 DWORD dwProtocol;
 DWORD dwSmacOffset;
 DWORD dwDmacOffset;
 DWORD dwTargetUserIDOffset;
 DWORD dwTargetDomainOffset;
 DWORD dwMessageIDOffset;
 DWORD dwTunnelOffset;
 DWORD dwInterfaceOffset;
 DWORD   dwMmemonicOffset;
 DWORD dwFlagOffset;
 DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
 DDWORD      ddwSessionId;
 DWORD dwStatusOffset;
 DWORD dwOpOffset;
 DWORD dwReasonOffset;
 DWORD dwEvtNum;
 DWORD   dwArgOffset;
 DWORD dwMsgOffset;
 DWORD dwDetailOffset;
 CHAR szContent[0];

}EVT_VPN,*PEVT_VPN;

typedef struct  _EVT_SECURE : public EVT_HEAD {
 DWORD dwCategoryOffset;
 DWORD dwSeverity;
 DWORD dwEvtTypeOffset;
 DWORD dwEvtSrcOffset;
 DWORD dwEvtUserOffset;
 DWORD dwSrcIp;
 DWORD dwSrcPort;
 DWORD dwDstIp;
 DWORD dwDstPort;
 DWORD dwProtocol;
 DWORD dwFlagOffset;
 DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
 DDWORD ddwSessionId;
 DWORD dwRuleOffset;
 DWORD dwStatusOffset;
 DWORD dwOpOffset;
 DWORD dwReasonOffset;
 DWORD dwEvtId;
 DWORD dwEvtNum;
 DWORD   dwSignatureOffset;
 DWORD dwDetailOffset;
 CHAR    szContent[0];
}EVT_SECURE,*PEVT_SECURE;

这些类型实际上是同一类类型,实际上可以从同一个类派生,使用 PullUp Member 方法重构。但是这些结构已经发布,不可能施行这种重构。可以这样:

class CEventWrapper
{
public:
 CEventWrapper(PEVT_HEAD p) { m_p = p; }

 struct NetInfo
 {
  DWORD dwDstIp;
  DWORD dwDstPort;
  DWORD dwSrcIp;
  DWORD dwSrcPort;
  DWORD dwProtocol;
  TCHAR szDstMac[20];
  TCHAR szSrcMac[20];
 };
 BOOL GetNetInfo(NetInfo* p) const;
 template static void
  TemplateGetNetInfo(CEventWrapper::NetInfo* netInfo, const T& x)
 {
  netInfo->dwDstIp  = x.dwDstIp;
  netInfo->dwDstPort = x.dwDstPort;
  netInfo->dwSrcIp  = x.dwSrcIp;
  netInfo->dwSrcPort = x.dwSrcPort;
  netInfo->dwProtocol = x.dwProtocol;
 }

 BOOL   HasNetInfo() const;

private:
 PEVT_HEAD m_p;
};

BOOL CEventWrapper::HasNetInfo() const
{
 NetInfo ni;
 return GetNetInfo(&ni);
}

BOOL CEventWrapper::GetNetInfo(NetInfo* netInfo) const
{
 memset(netInfo, 0, sizeof(NetInfo));

 switch (m_p->dwLogFrt)
 {
 default:
  ASSERT(0);
  return FALSE;
 case DIAL_LOG:
 case WEBTRENDS_LOG:
 case SNORT_LOG:
 case SENDMAIL_LOG:
 case SYSLOG:
 case NETSCREEN_LOG:
 case WIN_FILE_LOG:
 case WIN_PROCESS_LOG:
 case APACHE_ERROR_LOG:
 case IP_MON_LOG:
 case IP_UP_LOG:
 case PROC_MON_LOG:
 case GENERAL_MON_LOG:
 case PERF_MON_LOG:
 case PORTMON_LOG:
  ASSERT(0);
  return FALSE;

 case EVENT_LOG:   return FALSE;

 case CP_LOG:
  TemplateGetNetInfo(netInfo, *(EVT_VIRUS*)(m_p + 1));
  return TRUE;
 case VPN_LOG:
  TemplateGetNetInfo(netInfo, *(EVT_VPN*)(m_p + 1));
  return TRUE;

 case SECEXPERT_LOG:  return FALSE;

 case IIS_FTP_LOG:  return FALSE;
 case EXCHANGE_LOG:  return FALSE;
 case FW_LOG:
  {
   EVT_FW* p = (EVT_FW*)(m_p + 1);
   TemplateGetNetInfo(netInfo, *p);
   if (p->dwDmacOffset)
    lstrcpyn(netInfo->szDstMac, p->dwDmacOffset + (char*)p,
     dimof(netInfo->szDstMac));
   if (p->dwSmacOffset)
    lstrcpyn(netInfo->szSrcMac, p->dwSmacOffset + (char*)p,
     dimof(netInfo->szSrcMac));
   return TRUE;
  }
 case DOMINO_HTTP_LOG:
 case APACHE_LOG:
 case IIS_HTTP_LOG:
  return FALSE;

 case CISCO_PIX_LOG:
 case CISCO_IOS_LOG:
 case CISCO_SWITCH_LOG:
 case HUAWEI_SWITCH_LOG:
 case NORTEL_SWITCH_LOG:
  TemplateGetNetInfo(netInfo, *(EVT_SWITCH*)(m_p + 1));
  return TRUE;

 case SQLSERVER_LOG:  
 case ORACLE_LOG:
 case MYSQL_LOG:
  return FALSE;

 case KIDS_LOG: case IDS_LOG:
  TemplateGetNetInfo(netInfo, *(EVT_SECURE*)(m_p + 1));
  return TRUE;
 }
 ASSERT(0);
 return FALSE;
}

C语言垃圾代码清除工具(含源码)

阅读更多关于《C语言垃圾代码清除工具(含源码)》

CodeClean 使用说明

 

1.      说明

工程中有许多垃圾代码,CodeClean能识别的垃圾代码指从入口不可达的垃圾函数和全局变量。CodeClean 可以扫描出所有这类代码,从扫描垃圾的角度,未对函数和全局变量未做区别。

有很多函数和全局变量被其它的函数或全局变量引用到,但引用它的函数(或全局变量)从入口是不可达的,这样的函数(或全局变量)称它为 Island

本程序仅扫描C语言(不包括C++)的垃圾代码。本程序不对C语言程序进行预处理(忽略了#”开头的行),对宏调用不做特别处理,将它看作是一个普通的函数调用。

对于已知的未使用的变量,或函数(如这些变量或函数在汇编语言程序中使用)。为防止他们被清除掉,可以定义一个哑宏,如:

#define  DUMMY_REFER(X)

在某个(已知的)从入口可达的函数(非垃圾函数)中引用该变量(或函数)即可。如:

Void main()

{

   …..

   DUMMY_REFER(MyPredefinedFunction);

   …..

}

2.      命令行

        CodeClean options

 

        options: /Fxxx option default is output file name

        island object is an object which is not reachable by ‘main’,

        but was refered by another object.

 

/Fmake [make file name(input file, list of input source file names)]

/Fgarbage [garbage object list file name]

/Fisland [island object file name]

/Ferror [error message output file name]

/Fcall [call graph file name]

/Dcall [max call graph depth (default is 32)]

/Ncall [max callees number each object’s call graph (default is 32)]

/Fcaller [caller graph file name]

/Dcaller [max caller graph depth (default is 32)]

/entry [entry point name (default is ‘main’)]

 

/allcaller (list all callers of each object, in spite of found ‘main’ or not)

/cleancode (generate clean code)

/onlyzero (only list zero refered object to garbage object file)

/tomain (list any callers of each object until found ‘main’ function)

/entrystop (same as ‘tomain’)

/? or /H or /h (show this help message)

3.      命令行详解

[ ] 括起来的地方,表示这里必须要有一个参数――如果有前面的 /xxxx 选项。

 

/Fmake [输入文件名,其中包含 *.C文件名列表,每行一个文件]

/Fgarbage [输出文件名,扫描出的垃圾对象列表]

/Fisland [输出文件名,扫描出的“island”对象列表]

/Ferror [输出文件名,扫描过程中的显示信息,默认是Consol屏幕]

/Fcall [对象调用图(从上往下)]

/Dcall [每个对象调用图的最大深度(默认是 32)]

/Ncall [每个对象调用图的最多只列出的调用对象的数目,默认列出全部]

/Fcaller [对象被调图(从下往上)]

/Dcaller [每个对象被调图的最大深度(默认是 32)]

/entry [入口函数的名字,默认是”main”]

/allcaller (列出每个对象的所有调用者,不管是否搜索已到入口)

/cleancode (生成干净代码,生成的干净代码与原代码在同一目录下,以 .cxx 为后缀名)

/onlyzero (仅列出未被使用的对象,不列出 “island”对象)

/tomain (被调图碰到入口函数就停止)

/entrystop (‘tomain’相同)

/? or /H or /h (显示这个帮助信息)

 

例:

CodeClean /tomain /entry MyMain /Fmake make.mak /Fgarbage garbage.txt /Fcaller caller.txt /Fcall call.txt

生成垃圾对象列表和被调图及调用图,其中MyMain是入口函数名, make.mak 是输入文件名,其中包含要扫描的文件名列表...

 

一个可能的 Mak 文件内容如下:

 

kernel/oss/kernel.c

kernel/oss/osinit.c

kernel/oss/os_err.c

kernel/oss/os_msg.c

kernel/oss/os_oem.c

kernel/oss/os_stat.c

kernel/oss/os_synch.c

kernel/oss/schtmr.c

 

 

4.      程序

如果您的VC(或其它编译环境)安装了STLPort,您可以定义__USE_HASP_MAP宏以便编译出最快的代码。

使用__USE_HASP_MAP,在Windows2000P42.8512M内存环境下,扫描2M代码只需要5!如果再生成去除垃圾后的干净代码,也只需要10钟。连我自己都对这个速度感到惊异!

 

源码下载

程序下载(该程序未使用__USE_HASP_MAP,速度不是最快

 

 

 

 

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

阅读更多关于《使用 C 语言的“准元程序”设计》

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

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

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

但是,在条件编译中:

因此,象这样的程序是错误的:

适应它,Play With Preprocessor

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

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

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

总体上讲,C++的元程序设计是函数式语言(类似 lisp),而C语言的元程序设计有点类似汇编语言,试看:

 

实例,实现函数

      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 多行!: 

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

C 语言几个绝招

阅读更多关于《C 语言几个绝招》

符号展开连接

CAT_TOKEN_1 将 t1 t2 连接成 t1t2 ,不预先将 t1 和 t2 展开,而

CAT_TOKEN_2 将 t1 和 t2 展开后再连接,如:

0转化为0,而将非零转化为 1,可以转化指针

编译时断言

定义 Handle类型

将 Handle 定义为函数指针主要有一个好处:就是禁止了对 Handle 的加减,防止了一些小错误的发生。

定义union中的匿名 struct

 

一个脚本语言编译器

阅读更多关于《一个脚本语言编译器》
 

  该编译器及运行环境采用虚拟机执行方式,即将源文件编译为中间代码(类似 Java 字节码),而中间代码在虚拟机(不是堆栈机,Java虚拟机是“准堆栈机”,大部分指令是堆栈式的,但为了效率,也有小部分指令不是堆栈式的)上执行。 可用于编译原理学习。

代码下载:http://febird.nease.net/OtherProduct/ScriptCompiler/ScriptEngine.rar

语言描述:http://febird.nease.net/OtherProduct/ScriptCompiler/Specification.htm

我的原文:http://febird.nease.net/OtherProduct/ScriptCompiler/ScriptCompiler.htm