2012年12月27日 星期四

Function Pointer - 函式指標

C 語言有一個強大的功能,Function Pointer (函式指標),在我真正了解它之前,只是覺得它能用指標來代表一個函式而已。但事實上並非如此,受到物件導向程式設計的影響,當我了解什麼是多型 (Polymorphism) 而且從中明白它的強大之處,再回頭想到 Function Pointer,它們是一樣的概念,都是能在程式執行中動態地改變函式 (Function) 或方法 (Method) 。那這為什麼重要?在「軟體建構之道 第二版」(Code Complete 2) 提到了軟體開發很重要的一件事:避免複雜度。隨著自己寫程式的時間越來越長,看別人寫得的程式碼也越來越多時,真的發現了一件事,程式碼越複雜越難維護;這也不是說系統很大,功能很多而造成程式碼很複雜,想想看 Linux kernel 有多大?一樣很有系統和結構。所以,撰寫程式絕對可以寫很簡單明瞭,也可以很複雜,全在於程式設計師本身的功力而已。

回到正題,函式指標到底可以多好用?先從最基本的開始吧!


int add(int x, int y)
{
    return x+y;
}

int sub(int x, int y)
{
    return x-y;
}

int main(void)
{
    int (*pfunc)(int, int);

    pfunc = add;
    printf("sum = %d\n", pfunc(3, 2));
    pfunc = sub;
    printf("dif = %d\n", pfunc(3, 2));

    return 0;
}

上面其實不算什麼應用,只是用來說明函式指標的用法,和直接使用 add 和 sub 函式沒有什麼差別。再看底下的例子:

int add(int x, int y)
{
    return x+y;
}

int sub(int x, int y)
{
    return x-y;
}

int calc(int (*pfunc)(int, int), int x, int y)
{
   return pfunc(x, y);
}

int main(void)
{

    printf("sum = %d\n", calc(add, 4, 2));
    printf("dif = %d\n", calc(sub, 4, 2));

    return 0;
}

藉由 calc 這個函式,它把  int (*pfunc)(int, int) 當做參數,讓 add 和 sub 可以直接傳給 calc,讓它做你要它做的事。

int add(int x, int y)
{
    return x+y;
}

int sub(int x, int y)
{
    return x-y;
}

int mul(int x, int y)
{
    return x*y;
}

int div(int x, int y)
{
    return x/y;
}

enum op_type { ADD, SUB, MUL, DIV };
typedef struct {
    char *op_name;
    int x;
    int y;
    enum op_type op;
} parameters;

int(*perform_feature[])(int, int) = {add, sub, mul, div};


int main(void)
{
    int i;

    parameters p[] = {
        {"sum", 4, 2, ADD},
        {"dif", 4, 2, SUB},
        {"pro", 4, 2, MUL},
        {"quo", 4, 2, DIV},
    };

    for (i=0;i<(int)(sizeof(p)/sizeof(parameters));i++)
        printf("%s = %d\n", p[i].op_name, (perform_feature[p[i].op])(p[i].x, p[i].y));

    return 0;
}


最後這個例子因為 for 迴圈無法用 code 的方式顯示,所以直接貼上。在這裡加上陣列的使用,讓函式直接利用索引來執行,這樣的好處是,不管我新增了多少新的函式到 perform_feature 裡,都不用改 for 迴圈。

這裡的例子只是一小部份應用,如何能應用到你的程式裡,就要靠你的設計能力了。

沒有留言:

張貼留言