EDIT:从答案中得出的最相关的结论是……不:你不能,因为void*和struct*的指针在内存中的表示可能会有所不同。这很罕见,但标准并不禁止。这是我找到的最好的标准引用:
https://stackoverflow.com/a/1241314/1087626
在下面的模拟示例中,我试图构建一个
generic_processor
接口,调用者将对象指针传递到
void*
处理器中的参数,调用者显式地将“操作”转换为
void(*gfp)(void)
(通用函数指针),这是
通用处理器
期待。
对于跨类型的每个操作,“具体操作”都有几乎相同的签名,因为它们接受一个对象指针,可能还有其他一些参数,并返回一个
int
请注意,具体操作采用对象指针
混凝土类型
.
以下是我怀疑的关键步骤:
通用处理器
铸造
gfp
函数指针的参数
typedef
具有与具体动作功能匹配的签名
除了对象指针现在是
无效*
.
正如这个答案中引用的:
https://stackoverflow.com/a/189126/1087626
-
766指向一种类型的函数的指针可以转换为指向另一种类型函数的指针,然后再转换回来;
-
767,结果应与原始指针相等。
-
768如果使用转换后的指针调用类型与所指向类型不兼容的函数,则行为未定义。
所以,问题的核心是:在这种情况下,“不兼容”是什么意思?
在the
通用处理器
我正在转换一个与原始具体签名相同的函数指针签名,除了它有一个
无效*
作为第一个参数,而不是
circle*
或
square*
.
这定义得好吗?
模拟示例:
#include <stdio.h>
// types
typedef struct {
int a;
double d;
} circle;
typedef struct {
int b;
float f;
} square;
// ... 10 types,.. different sizeof()
// concrete API
int open_circle(circle* c) {
printf("opening circle: %d: %f\n", c->a, c->d);
return c->a;
}
int open_square(square* s) {
printf("opening square: %d: %f\n", s->b, s->f);
return s->b;
}
int send_circle(circle* c, const char* msg) {
printf("sending circle: %d: %f: %s\n", c->a, c->d, msg);
return -c->a;
}
int send_square(square* s, const char* msg) {
printf("sending square: %d: %f: %s\n", s->b, s->f, msg);
return -s->b;
}
// ten more operations for each type
// "genericised" function pointer types (note the void* params!!)
typedef int (*open_fpt)(void* o);
typedef int (*send_fpt)(void* o, const char*);
typedef void (*gfp)(void); // generic function pointer
int generic_processor(void* obj, gfp open, gfp send) {
int sum = 0;
sum += ((open_fpt)open)(obj);
sum += ((send_fpt)send)(obj, "generically sent");
return sum;
}
int main() {
circle c = {2, 22.2};
square s = {3, 33.3F};
int net = 0;
net += generic_processor(&c, (gfp)open_circle, (gfp)send_circle);
net += generic_processor(&s, (gfp)open_square, (gfp)send_square);
printf("net %d\n", net);
return 0;
}
使用gcc 13.2编译:运行良好,无警告:
gcc -std=c99 -g -o gfp tests/gfp.c -Wall -Wextra -pedantic -fsanitize=address,leak,undefined && ./gfp
opening circle: 2: 22.200000
sending circle: 2: 22.200000: generically sent
opening square: 3: 33.299999
sending square: 3: 33.299999: generically sent
net 0