为什么在这种情况下我需要避免 "casting a function pointer to a generic pointer"?

Why do I need to avoid "casting a function pointer to a generic pointer" in this case?

假设我有一个以函数指针作为成员的结构:

struct Class
{
    void (*function)();
}

然后我想给这个成员分配一个功能。我想这样做:

typedef void (*func_pointer)();
func_pointer method = va_arg(arg_list, func_pointer);
struct Class foo;

因为 foo.functionmethod 的类型都是 void (*)() (“通用”函数指针)我假设我可以把它们等同起来,比如 foo.function = method.

但是,我正在阅读的书提到 ANSI C“不允许我们”在“void *”和“函数指针”之间转换。 (Object Oriented Programming with ANSI C, chapter 6, page 64) 因此他们做了这样的事情:

*(func_ptr*) &foo.function = method;

为什么?为什么有必要?我在这里没有看到任何 void * 指针。为什么我不能直接将 method 的值复制到 foo.function

由于本书中的代码相当复杂,我试图对其进行简化,但这可能已经改变了上下文,这是真正的代码:(完整代码在 git repo 中,如果您想看一下, 文件 Object.c.)

struct Class
{
    const struct Object _;
    const char * name;
    const struct Class * super;
    size_t size;
    void * (*ctor)(const void * self, va_list * arg_ptr);
    void * (*dtor)(const void * self);
    int (*differ)(const void * self, const void * other);
    int (*puto)(const void * self, FILE * file_ptr);
};
{
        typedef void (*voidf) (); /* generic function pointer */
        voidf selector;
        va_list ap = *app;
        while ((selector = va_arg(ap, voidf)))
        {
            voidf method = va_arg(ap, voidf);
            if (selector == (voidf) ctor)
                *(voidf *) &self — > ctor = method;
            else if (selector == (voidf) dtor)
                *(voidf *) &self — > dtor = method;
            else if (selector == (voidf) differ)
                *(voidf *) &self — > differ = method;
            else if (selector == (voidf) puto)
                *(voidf *) &self — > puto = method;
        }
        return self;
    }

在这种情况下,我的想法是只做一个 self->ctor = method 就足够了。

我不会在 typedef 后面隐藏任何指针(甚至是函数指针)。它使代码难以阅读且容易出错。

typedef void func();

struct Class
{
    func *fptr;
};

struct Class bar(int x, ...)
{
    va_list va;
    func *fp;
    struct Class c;

    va_start(va, x);
    fp = va_arg(va, func *);
    c.fptr = fp;

    return c;
}

您不需要任何转换。

你的代码没有问题,书上那段也没有问题。 “问题”是该段落不适用于您的代码。

the book I'm reading mentioned that casting between "void *" and a "function pointer" is illegal.

这是真的。参见 this question/answer

但是在您的代码中没有 void*foo.function 是一个 void(*)()(指向接受任意数量参数并返回 void 的函数的指针),它与 func_pointer 的类型相同。所以没有必要做任何类型的铸造。 foo.function = method; 正确。

编辑

从您添加到问题中的说明来看,这本书似乎在说一些类似的话:“使用 void* 我们可以避免很多丑陋的转换类型,但由于 ANSI C 不允许 void* 保存函数指针,我们无法避免这些类型转换。"

简化书中的一个例子:

struct Class {
    void * (*ctor)(const void * self, va_list * arg_ptr);
};
struct Class self;

typedef void (*voidf)();
voidf method = ...;

*(voidf*)&self.ctor = method;

强制转换是必要的,因为 self.ctorvoid* (*)(const void*, va_list*),而不是 void(*)()

如果你可以在这里使用void*,你可以改为:

void *method = ...;
self.ctor = method;

不做任何转换。