void*可以用来存储函数指针吗?

18

void*被定义为可以指向任何东西,那么它能否用来指向一个函数(比如int send())?

int send();
void* p = send;

这是可能的吗?当我像这样使用时,它没有显示错误,为什么?如果不行,有没有办法将所有指针存储在一个变量中?


3
不,void* 类型与函数指针不兼容。 - user2249683
我认为这是可能的。 - Venkatesh
7
void* 的定义是可以容纳任何数据指针。函数指针(以及对于 C++ 中的成员指针)则完全不同。尽管 POSIX 允许将函数指针赋值给 void*(在 C 标准的 J.5.7 函数指针转换 中甚至被列为常见扩展)。 - Deduplicator
1
在任何特定的实现中都可能是可行的(例如在大多数编译器可以使用的x86上),但这并不意味着标准允许它(我认为标准并不允许)。 - dmckee --- ex-moderator kitten
@dmckee 实际上,我在x86上遇到了最多的问题。想想旧的far/near问题以及编译模型,其中函数指针是far,但数据指针是near,或者反之亦然。 - James Kanze
2个回答

21
也许吧。在C++11之前是无法转换的,但是C++11增加了以下内容:

将函数指针转换为对象指针类型或反之亦然是有条件支持的。这种转换的含义是实现定义的,除非一个实现同时支持两个方向的转换, 将一个类型的prvalue转换为另一个类型并返回,可能具有不同的cvqualification,应产生原始指针值。

这似乎没有被纳入C中。

当然,你不能相互转换它们的原因是它们可能没有相同的大小或格式。Posix要求它们具有相同的大小和格式,并且我希望所有Posix编译器都支持转换;以前大多数人都这样做了,尽管这使它们不符合规范。

编辑:

更多信息。重新阅读C标准后,我认为对象指针和函数指针之间的转换是未定义的行为:C标准似乎不需要在这种情况下发出诊断,但它肯定不会为其定义任何行为。作为未定义的行为,一个实现(或Posix)可以自由定义它。或者就像不记录它一样随便做什么。

另一方面,C++在C++11之前需要发出诊断(尽管许多编译器没有发出诊断)。根据上面引用的段落,在C++11中,是否支持转换是实现定义的,如果一个实现支持它,它们必须记录其行为。因此,在所有情况下,实现都需要记录它所做的,并且如果代码尝试执行转换,则需要发出诊断。


这是最接近正确答案的,被接受的答案是错误的。对于标准C来说,它是未定义的;对于POSIX C来说,它被定义为可能的;对于C++11来说,它被定义为上述情况。至少GCC支持这个。 - sjdowling
@sjdowling:我没有看到被接受的答案有任何踩票。如果你认为它是错的,为什么不给它踩票呢? - Lightness Races in Orbit
1
@sjdowling 接受的答案对于 C 语言而言是正确的,就 ISO 标准而言。 (在几个地方,Posix 与 C 语言的 ISO 标准相矛盾。) - James Kanze

16
不,可能不行。
根据C标准(6.3.2.3 指针),一个指向void的指针可以转换为任何对象类型的指针,一个指向任何对象类型的指针可以转换为指向void的指针并再次转换回去,结果应该与原始指针相等。
至于函数指针,则可以将一种类型的函数指针转换为另一种类型的函数指针,然后再转换回来,结果应该与原始指针相等。如果使用转换后的指针调用与所引用类型不兼容的函数,则其行为未定义。
在C++标准中,指针有更详细的定义(3.9.2 复合类型)。指向void或对象类型的指针的类型称为对象指针类型... 可以指定函数的指针类型称为函数指针类型。
指向cv限定(3.9.3)或未限定的void的指针可用于指向未知类型的对象。 这样的指针应该能够保持任何对象指针。 类型为cv void *的对象应具有与cv char *相同的表示和对齐要求。

一个函数不是对象类型(虽然你可以将它放入lambda中)。 - user2249683
3
然而,POSIX要求定义转换,并且它们在大小和表示上必须相同,作为“dlsym”需求的一部分。 - R.. GitHub STOP HELPING ICE
不一定。在你的引用中没有提到“不一定”,它只是没有提到“可能”。 - newacct
@R 现在。早期版本的Posix在这个问题上有些模糊,而示例代码使用类似于*(void**)ptr = dlsym(...);的东西。 - James Kanze
@newacct 在C语言中,我不确定,但我认为转换是未定义行为(这意味着实现可以自由定义它)。至少,C标准似乎不需要诊断; 它只是没有定义任何行为(这使其成为未定义行为)。 - James Kanze
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接