簡體   English   中英

C中struct中的函數指針

[英]Function pointer in struct in C

我試圖使用struct在C中實現類的想法。 我的測試代碼:

#include <stdio.h>

typedef struct test_struct
{
    int data;
    void(*func)(struct test_struct *);
} test_t;

void inc_data(test_t * this)
{
    this->data++;
}

int main(void)
{
    test_t test = { 0, inc_data };

    test.func(&test);

    printf("%d\r\n", test.data);
}

工作正常,但我還需要1件事。 我希望函數func不需要struct test_struct *作為參數,只需調用test.func()

我該怎么做?

我認為我們可以使用#define替換test.func(&test)test.FUNC()但是我不知道該怎么做。

還有另外一個問題, this指針在C,不是C ++讀取類似,但它實際上是不同的。 我知道C中沒有this指針。我的問題是:是否有任何“技巧”可以做到這一點? 就像使用#define或其他方法一樣。 使用全局變量不是一個好的答案,因為我的程序中將有許多對象。

正如注釋中指出的那樣,當問題被標記為重復時,您可以使用預處理器,並非常接近您想要的內容。 它不是您指定的符號,但是C不是C ++。

您可以使用宏解決問題:

#define SCALL0(s, m)        ((s).m(&(s)))
#define SCALLn(s, m, ...)   ((s).m(&(s), __VA_ARGS__))
#define PCALL0(p, m)        ((p)->m(p))
#define PCALLn(p, m, ...)   ((p)->m((p), __VA_ARGS__))

在所有這些宏中, m參數是要調用的“成員函數”。 S宏用於s參數是實際結構時; P宏用於p參數是指向結構的指針時。 0宏用於成員函數僅采用this指針; n宏用於成員函數采用一個或多個其他參數的情況。 您可能會寫,例如:

SCALL0(test, func);

通過將address-of運算符應用於實際結構,您可能僅可以使用兩組宏之一,例如:

PCALL0(&test, func);

您可能願意為可變參數宏使用GCC特定於標准行為的擴展,以避免需要0-vs-n的區別:

#define PCALL(p, m, ...) ((p)->m((p), ## __VA_ARGS))

因此,如果您接受了降低的可移植性並且需要將&應用於結構……並且您接受了用於調用成員函數的宏符號,則PCALL宏可能是您唯一需要的宏。 它與C ++成員函數調用不同,但C與C ++不同。

示例代碼:

#include <stdio.h>

typedef struct test_struct
{
    int data;
    void (*func0)(struct test_struct *);
    void (*func1)(struct test_struct *, int);
} test_t;

#define SCALL0(s, m)        ((s).m(&(s)))
#define SCALLn(s, m, ...)   ((s).m(&(s), __VA_ARGS__))
#define PCALL0(p, m)        ((p)->m(p))
#define PCALLn(p, m, ...)   ((p)->m((p), __VA_ARGS__))
#define PCALL(p, m, ...)    ((p)->m((p), ## __VA_ARGS__))

static void inc_data(test_t *this) { this->data++; }
static void dbl_data(test_t *this) { this->data *= 2; }
static void add_data(test_t *this, int add) { this->data += add; }
static void mul_data(test_t *this, int mul) { this->data *= mul; }

int main(void)
{
    test_t test = { 0, inc_data, add_data };
    test_t *pt1 = &(test_t){ 100, inc_data, add_data };
    test_t *pt2 = &(test_t){ 10, dbl_data, mul_data };
    test_t *pt3 = &(test_t){ -27, dbl_data, add_data };

    printf("Test SCALL0, SCALLn on structure:\n");
    printf("%d\n", test.data);
    test.func0(&test);
    printf("%d\n", test.data);
    test.func1(&test, 7);
    printf("%d\n", test.data);
    SCALL0(test, func0);
    printf("%d\n", test.data);
    SCALLn(test, func1, 100);
    printf("%d\n", test.data);

    printf("Test PCALL0, PCALLn on pointer:\n");
    printf("%d\n", pt1->data);
    pt1->func0(pt1);
    printf("%d\n", pt1->data);
    pt1->func1(pt1, 22);
    printf("%d\n", pt1->data);
    PCALL0(pt1, func0);
    printf("%d\n", pt1->data);
    PCALLn(pt1, func1, test.data);
    printf("%d\n", pt1->data);

    printf("Test PCALL0, PCALLn on another pointer:\n");
    printf("%d\n", pt2->data);
    pt2->func0(pt2);
    printf("%d\n", pt2->data);
    pt2->func1(pt2, 22);
    printf("%d\n", pt2->data);
    PCALL0(pt2, func0);
    printf("%d\n", pt2->data);
    PCALLn(pt2, func1, pt1->data);
    printf("%d\n", pt2->data);

    printf("Test PCALL on structure:\n");
    printf("%d\n", test.data);
    test.func0(&test);
    printf("%d\n", test.data);
    test.func1(&test, 22);
    printf("%d\n", test.data);
    PCALL(&test, func0);
    printf("%d\n", test.data);
    PCALL(&test, func1, pt1->data);
    printf("%d\n", test.data);

    printf("Test PCALL on pointer:\n");
    printf("%d\n", pt3->data);
    pt3->func0(pt3);
    printf("%d\n", pt3->data);
    pt3->func1(pt3, pt1->data);
    printf("%d\n", pt3->data);
    PCALL(pt3, func0);
    printf("%d\n", pt3->data);
    PCALL(pt3, func1, pt2->data);
    printf("%d\n", pt3->data);

    return 0;
}

樣本輸出:

Test SCALL0, SCALLn on structure:
0
1
8
9
109
Test PCALL0, PCALLn on pointer:
100
101
123
124
233
Test PCALL0, PCALLn on another pointer:
10
20
440
880
205040
Test PCALL on structure:
109
110
132
133
366
Test PCALL on pointer:
-27
-54
179
358
205398

您可以創建和使用SCALL宏,但是最好改用PCALL宏。

在您試圖模仿的C ++中,有一個隱式this指針作為每個方法的參數。 如果您的結構中沒有類似的指針,則在調用方法時必須訪問全局數據,這是一個壞主意。

您的職能

void inc_data(test_t * this)
{
  this->data++;
}

具有該參數,但是它依賴於您在調用函數時提供參數。 如果要刪除它

void inc_data()
{...}

然后,由於該函數與該結構的內容之間沒有明確的關系,因此該函數將需要對全局數據進行操作。

我建議-正如其他人已經做過的那樣,嘗試C ++而不是重新發明輪子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM