[英]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.