• 2006-05-13

    自娱自乐的代码

    Tag:向下走

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/2464484.html

    为了与实验板子进行性能比较,我们需要测试一下PC上几种基本运算的性能。在我为int写完+运算的代码之后,Copy&Paste几份,修修改改提供了-、*、/,一个同事站在了我的背后。“这得写多少啊!”。一句话提醒了我,摆着手指头一算,还有long、float、double的运算要写,CP大法不划算。于是,改写出下面的代码。

    #include <windows.h>
    #include <stdio.h>

    typedef double TestFun();

    __int64 FileTimeToQuadWord(PFILETIME pFileTime)
    {
     __int64 qw;
     qw = pFileTime->dwHighDateTime;
     qw <<= 32;
     qw |= pFileTime->dwLowDateTime;
     return(qw);
    }

    #define COUNTER 100000000

    #define TEST_FUNC(type, op_name, op) \
    double Test##type##op_name() { \
        HANDLE hHandle = GetCurrentThread(); \
        FILETIME ftCreationTime; \
        FILETIME ftExitTime; \
        FILETIME ftKernelTimeStart; \
        FILETIME ftKernelTimeEnd; \
        FILETIME ftUserTimeStart; \
        FILETIME ftUserTimeEnd; \
        BOOL bFlag; \
        __int64 qwStartTime; \
        __int64 qwEndTime; \
        __int64 qwUserTimeElapsed; \
        type a = 1; \
        type b = 2; \
        type result; \
        long i; \
        bFlag = GetThreadTimes(hHandle, \
                               &ftCreationTime, \
                               &ftExitTime, \
                               &ftKernelTimeStart, \
                               &ftUserTimeStart); \
        for(i = 0 ; i < COUNTER ; i++) { \
            result = a op b;  \
        } \
        bFlag = GetThreadTimes(hHandle, \
                               &ftCreationTime,  \
                               &ftExitTime, \
                               &ftKernelTimeEnd, \
                               &ftUserTimeEnd);   \
        qwStartTime = FileTimeToQuadWord(&ftUserTimeStart); \
        qwEndTime = FileTimeToQuadWord(&ftUserTimeEnd); \
        qwUserTimeElapsed = qwEndTime - qwStartTime; \
        double ResultTime = qwUserTimeElapsed / 10000.0; \
        return ResultTime / COUNTER;\
    }

    #define TEST_FUNC_TYPE(type) \
        TEST_FUNC(type, Add, +) \
        TEST_FUNC(type, Sub, -) \
        TEST_FUNC(type, Mul, *) \
        TEST_FUNC(type, Div, /)

    TEST_FUNC_TYPE(int)
    TEST_FUNC_TYPE(long)
    TEST_FUNC_TYPE(float)
    TEST_FUNC_TYPE(double)

    void StatTest(char *tips, TestFun func) {
        double result = func();
        printf("%s %fms\n", tips, result);
    }

    #define makechar(x)  #x

    #define STAT_TEST(type, op_name) \
        StatTest(makechar(type##op_name), Test##type##op_name)

    #define STAT_TEST_TYPE(type) \
    do { \
        STAT_TEST(type, Add); \
        STAT_TEST(type, Sub); \
        STAT_TEST(type, Mul); \
        STAT_TEST(type, Div); \
    } while(0)

    int main(int argc, char** argv) {
        STAT_TEST_TYPE(int);
        STAT_TEST_TYPE(long);
        STAT_TEST_TYPE(float);
        STAT_TEST_TYPE(double);

        return 0;
    }

    程序里用了一大堆宏,按照后来一个同事的说法,有些过。不过,这只是一些测试的代码,这么写最初只是为了好玩。

    其实,这算不上什么高级的用法,Python的源码中就有用类似的手法定义函数。实际上,预处理不应该被算作C语言本身的一部分,它可以看作是一种独立的语言。这种语言为我们提供了一种消除重复代码的机制,而这种技术实际上就是一种代码生成。当然,因为预处理的存在会让我们编写的源码和实际由C语言编译器处理的代码有所差别,会影响到代码的调试,而且乱用预处理会让代码变得异常难懂。我见过一些混乱的C代码,预处理常常在其中扮演重要的角色。

    预处理是把双刃剑,用成什么样,看自己了。

    分享到:

    历史上的今天:

    技术的风险 2004-05-13
    引用地址: