为什么在这种情况下我需要避免 "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.function
和 method
的类型都是 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.ctor
是 void* (*)(const void*, va_list*)
,而不是 void(*)()
。
如果你可以在这里使用void*
,你可以改为:
void *method = ...;
self.ctor = method;
不做任何转换。
假设我有一个以函数指针作为成员的结构:
struct Class
{
void (*function)();
}
然后我想给这个成员分配一个功能。我想这样做:
typedef void (*func_pointer)();
func_pointer method = va_arg(arg_list, func_pointer);
struct Class foo;
因为 foo.function
和 method
的类型都是 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.ctor
是 void* (*)(const void*, va_list*)
,而不是 void(*)()
。
如果你可以在这里使用void*
,你可以改为:
void *method = ...;
self.ctor = method;
不做任何转换。