您可以通过简单地 == 它们来检查两个函数指针是否相等,因为它们只是普通指针。这很明显。
但是,当您说“比较”时,请检查您的真实想法:
- 您是否有兴趣检测到您被赋予了不同的“东西”
- 或者你有兴趣检测你被赋予了不同的功能吗?
比较指针(不仅是函数指针!它适用于所有指针)有点冒险:您不是在检查内容(逻辑标识),而只是检查位置(“物理”标识)。大多数时候它确实是一样的,但有时,要小心,你会偶然发现副本。
很明显,如果您创建一个编号为 1、2、3、4 的数组,然后分配另一个数组并将内容复制到那里,那么您会得到两个不同的指针,对吧?但是该数组可能对您来说是相同的,这取决于您需要它的用途。
对于函数指针,问题是一样的,甚至更多:您实际上并不知道编译器/链接器对您的代码做了什么。它可能优化了一些东西,它可能将一些未导出的函数合并在一起,如果它注意到它们相等,它可能复制或内联其他函数。
尤其是在处理更大的单独“子项目”时可能会发生这种情况。想象一下,您编写了一个排序函数,然后将其包含在子项目 A 和子项目 B 中,编译/构建所有内容,然后链接并运行。你会以一种或两种功能结束吗?在您真正检查并正确调整链接选项之前,这是一个难题。
这比数组复杂一些。对于数组,如果数组不同,您将获得不同的指针。这里,同一个函数可能有很多不同的地址。在C++ 中使用模板时可能会特别明显,但这又取决于链接器的工作表现如何。哦,很好的例子:DLL。使用基于相似代码的三个 DLL,他们几乎可以保证拥有静态链接到的所有内容的三个副本。
当谈论 DLL 时……您知道它们可以将其他代码加载/卸载到您的内存中,对吗?这意味着当您加载 DLL 时,在某个地址 XYZ 处会出现一个函数。然后你卸载它,它就消失了。但是当你现在加载不同的 DLL 时呢?当然,操作系统可以重新使用空间,并且可以将新加载的 DLL 映射到与前一个相同的区域。大多数时候你不会注意到它,因为新加载的 DLL 将被映射到不同的区域,但它可能会发生。
这意味着虽然您可以比较指针,但您得到的唯一答案是:指针是否相同?
编辑跟进:
除非您(或您使用的某些库)曾经卸载DLL,否则您的指向函数的指针是安全的。
一旦加载了 DLL,唯一能改变这个 DLL 所占用的地址含义的坏事就是卸载动态模块。
如果您确定:
- (1)您的指向函数的指针不针对动态模块中的函数(仅指向静态链接的代码)
- (2) 或者它以动态模块为目标,但该动态模块永远不会被卸载(好的:直到程序退出或崩溃)
- (3) 或者它以动态模块为目标,并且您确切知道哪个动态模块,并且该动态模块有时会在运行时卸载,但是您的代码会收到有关该事实的一些“事先通知”
那么您的函数指针可以安全地存储、使用和比较,前提是您添加了一些安全措施:
- 对于 (1),不需要安全措施:功能不会被替换
- 对于(2),不需要安全措施:直到程序退出才能获得功能
- 对于(3),需要采取安全措施:您必须听取这些通知,一旦您收到有关 DLL 被卸载的通知,您必须立即忘记所有指向 DLL 的指针。您仍然可以安全地记住其他任何内容。当它再次加载时,您仍然可以安全地重新记住它。
如果您怀疑指向函数的指针确实以动态模块中的函数为目标,该函数将在程序退出之前的某个时间点卸载,并且:
- 您实际上并不知道该指针指向哪个 DLL
- 或者该 DLL 将在任何时候被卸载,恕不另行通知
那么你的函数指针根本无法安全使用。我的意思是无论如何。不要储存它,因为它可能会立即蒸发。