为啥指向成员函数的指针不像数据指针那样只是内存地址

Posted

技术标签:

【中文标题】为啥指向成员函数的指针不像数据指针那样只是内存地址【英文标题】:Why aren't pointers to member functions just memory address like data pointers为什么指向成员函数的指针不像数据指针那样只是内存地址 【发布时间】:2014-04-18 07:19:31 【问题描述】:

我从this 常见问题解答条目中意识到,无法将指向成员函数的指针转换为void* 或从void* 转换。指向成员的指针与指向数据的指针完全不同的内存地址!为什么这样?请帮我澄清一下。这不一定是成员函数,任何普通的 C 函数也是如此,不是吗?

【问题讨论】:

恕我直言 - C++ 中指向函数的指针是个坏主意,因为有更好的选择。 (虚函数和继承) 查看下一个常见问题条目Can I convert a pointer-to-function to a void*? 恕我直言,在 C 和 C++ 中使用 void * 也是一个坏主意 @EdHeal,在 C 中它可能是实现某种多态性的唯一方法。 @Jefffrey - 我同意,但最好避免 【参考方案1】:

指向成员的指针与指向数据的指针完全不同!为什么这样?

指向成员函数的指针需要指明该函数是否为虚函数,如果是则允许虚分派(可能通过指定到 vtable 的索引,而不是特定函数的地址)。这使得它们不仅仅是一个地址。

这不一定是成员函数,任何普通的 C 函数也是如此,不是吗?

指向“普通”(非成员)函数的指针可以转换为对象指针,但不可移植。引用标准:

C++11 5.2.10/8 有条件地支持将函数指针转换为对象指针类型,反之亦然。这种转换的含义是实现定义的,[...]

在许多平台上,(非成员)函数指针只是一个内存地址,并且转换是明确定义的。一些平台具有更奇特的内存架构 - 例如,指令和数据的单独内存空间 - 在这些平台上可能不允许转换。

【讨论】:

函数和数据的分隔空间是有意义的。但是,所有实体都应该解析为一个地址,不是吗?为什么禁止转换成函数所在的地址? @Prabhu:因为您假设指向成员函数的指针指向函数空间,但不一定如此。为了实现对virtual 指针和virtual 继承的支持,它们可能携带数据 @Prabhu:“所有实体都应该解析为一个地址”——如果指令和数据有单独的地址空间,则不会。指令空间中的地址不能用作数据空间中的地址,因此不应转换为 1。 您的问题似乎是关于指向 member functions 而不仅仅是 members 的指针 - 从标题中不清楚。 @Prabhu,大多数微控制器都遵循哈佛模型,具有独立的程序和数据地址空间。程序地址空间通常是线性的,但数据地址空间通常使用存储库切换来实现。因此,指向数据空间的指针与指向地址空间的指针具有完全不同的表示形式,前者是复杂对象,而不仅仅是数字。【参考方案2】:

在 C++ 标准中

正如next FAQ 所说:

该语言不要求函数和数据位于相同的地址空间中,因此,作为示例而非限制,在将它们放在不同地址空间中的架构上,两种不同的指针类型将无法比较。

在第 5.2.10/8 节(特别是 N3936)中,该标准规定这确实是定义的实现

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

这里的行为已经很好地说明了。

在 C 标准中

C 标准似乎没有考虑从函数指针到对象指针的转换。事实上,它几乎没有在它们之间划清界限。

它只是在 §6.3.2.3/8 中声明:

指向一种类型的函数的指针可以转换为指向另一种类型的函数的指针,然后再返回;结果应与原始指针比较。如果转换后的指针用于调用类型与引用类型不兼容的函数,则行为未定义。

此时的行为似乎未指定

然后在 §6.5.9/6 中:

两个指针比较相等当且仅当两个指针都是空指针,都是指向同一个对象(包括一个指向一个对象和一个在其开头的子对象)或函数的指针,两者都是指向最后一个元素的指针相同的数组对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的开头的指针,该数组对象恰好紧跟在地址空间中的第一个数组对象之后。

在这里我们可以看到实际差异的唯一痕迹:

两个指针比较相等当且仅当它们都是[..]指向同一个对象的指针(..)函数[..]。

为什么

至于“为什么”,它似乎取决于某些架构只是在两个地址空间中具有函数和对象的事实。

【讨论】:

在某些 x86-16 内存模型中,数据和函数指针甚至可以是不同的大小

以上是关于为啥指向成员函数的指针不像数据指针那样只是内存地址的主要内容,如果未能解决你的问题,请参考以下文章

C语言中 内存消亡 指向她的指针就一定消亡或成了空指针为啥是错的啊

为啥我不能访问指向数组中成员函数的指针?

结构体指针在使用完free后,该指针所指向的内存区域是啥,这个指针是变成了NULL,还是野指针。

为啥指针+1包含的内存地址与被指向的值的地址+1不同

为啥指向基类的派生类指针可以调用派生类成员函数? [复制]

内存、指针和指向指针的指针