C 語言中的函式指標

Jinku Hu 2023年1月30日 2021年1月22日
  1. 在 C 語言中使用 void (*func)() 符號來定義函式指標
  2. 使用函式指標陣列實現型別通用程式設計特性
C 語言中的函式指標

本文將介紹如何在 C 語言中使用函式指標。

在 C 語言中使用 void (*func)() 符號來定義函式指標

函式指標是 C 語言程式設計中的又一個結構,它實現了動態函式呼叫、結中包含自己的方法等高階功能,類似於物件導向設計、型別通用程式設計等。需要注意的是,函式指標的宣告可能有複雜的語法,即 void(*func)(void) 記號宣告瞭指向 void 函式的指標,該函式不需要引數。雖然在下面的例子中,我們將取單一 int 引數的 printInt 函式的地址分配給 void(*func)(void) 型函式指標。一旦定義了名為 func 的函式指標,就可以用通常的函式呼叫符號 func(arg) 或用 dereferencing 運算子 (*func)(arg) 來呼叫它。

#include <stdio.h>
#include <stdlib.h>

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

int main() {
    int input1 = 10233;

    void (*func)(int) = printInt;

    func(input1);
    (*func)(input1);

    exit(EXIT_SUCCESS);
}

輸出:

printed from printInt: 10233
printed from printDouble: 11.234000

另外,我們也可以使用 typedef 為函式指標定義一個新的型別別名,使程式碼更易讀。注意,不同的函式型別需要單獨的 typedef 語句。在下面的程式碼示例中,我們定義了一個沒有任何引數的 void 函式指標,儘管如此,printIntprintDouble 函式地址都儲存在型別為 FuncPtr 的變數中。需要注意的是,特定函式的地址可以通過顯式的&運算子或函式名本身的隱式賦值來獲取,這在下一個例子中有所體現。

#include <stdio.h>
#include <stdlib.h>

typedef void (*FuncPtr)();

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

void printDouble(double x)
{
    printf("printed from printDouble: %f\n", x);
}

int main() {
    int input1 = 10233;
    double input2 = 11.234;

    FuncPtr func1 = printInt;
    FuncPtr func2 = printDouble;

    func1(input1);
    func2(input2);

    exit(EXIT_SUCCESS);
}

輸出:

printed from printInt: 10233
printed from printDouble: 11.234000

使用函式指標陣列實現型別通用程式設計特性

像其他物件一樣,可以用括號 [] 符號定義一個函式指標陣列。在執行時可以利用這個陣列方便地選擇和呼叫特定的函式。請注意,我們使用的是關鍵字 _Generic,它是 switch 一樣的表示式,讓使用者根據控制表示式的型別評價來選擇具體的情況。因此,我們實現了下面的程式碼示例,根據 switch 條件中傳遞的變數型別,呼叫相應的 print 函式。請注意,enum 型別也被用來定義不同情況下的常量值。

#include <stdio.h>
#include <stdlib.h>

enum TYPE {INTEGER, DOUBLE, INVALID};

#define typename(x) _Generic((x), \
          int: INTEGER, \
        double: DOUBLE, \
      default: INVALID)

typedef void (*FuncPtr)();

void printInt(int x)
{
    printf("printed from printInt: %d\n", x);
}

void printDouble(double x)
{
    printf("printed from printDouble: %f\n", x);
}

int main() {
    int input1 = 10233;
    double input2 = 11.234;

    FuncPtr func_ptrs[] = {printInt, printDouble};

    switch (typename(input1)) {
        case INTEGER: func_ptrs[INTEGER](input1); break;
        case DOUBLE: func_ptrs[DOUBLE](input1); break;
        case INVALID: printf("No corresponding type found!\n");
        default: break;
    }

    switch (typename(input2)) {
        case INTEGER: func_ptrs[INTEGER](input2); break;
        case DOUBLE: func_ptrs[DOUBLE](input2); break;
        case INVALID: printf("No corresponding type found!\n");
        default: break;
    }

    exit(EXIT_SUCCESS);
}

輸出:

printed from printInt: 10233
printed from printDouble: 11.234000
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn

相關文章 - C Pointer