Alc*_*ott 5 c function-pointers
这是事情,我有几个功能,
void foo() {}
void bar() {}
Run Code Online (Sandbox Code Playgroud)
我想像普通对象的指针一样传递这些函数,
int main()
{
void (*fptr1)() = foo;
void (*fptr2)() = fptr1;
void (*fptr3)() = bar;
if (fptr1 == foo)
printf("foo function\n");
if (fptr2 == foo)
printf("foo function\n");
if (fptr3 == foo)
printf("foo function\n")
}
Run Code Online (Sandbox Code Playgroud)
我可以这样使用这些函数指针吗?我写了一个测试它的程序,好像没问题.此外,我认为,不像普通对象可能位于stack或者heap,函数驻留在text segment(对吗?)中,所以当我提到foo它时,它是否给了我函数foo在文本段中的物理地址?
跟进
如果我确实使用DLL,请考虑这个:首先,为函数ptr fptr分配一个函数,
ReturnType (*fptr)(ArgType) = beautiful_func;
Run Code Online (Sandbox Code Playgroud)
这里有两个场景,
1)如果beautiful_func不在DLL中,那么使用它是安全的fptr.
2)如果它在DLL中,那么以后,我认为使用它是不安全的fptr,因为它现在可能指的是一个完全不同的功能,它不是fptr天生的,对吧?
您可以通过简单地 == 来检查两个函数指针是否相等,因为它们只是普通指针。这是显而易见的。
然而,当你说“比较”时,检查一下你的真实想法:
比较指针(不仅是函数指针!它适用于所有指针)有点冒险:您没有检查内容(逻辑标识),而只是检查位置(“物理”标识)。大多数时候它确实是相同的,但有时要小心,你会偶然发现副本。
很明显,如果您创建一个包含数字 1,2,3,4 的数组,然后分配另一个数组并将内容复制到那里,那么您会得到两个不同的指针,对吧?但该阵列对您来说可能是相同的,具体取决于您需要它的用途。
对于函数指针,问题是相同的,甚至更多:您实际上不知道编译器/链接器对您的代码做了什么。它可能优化了一些东西,如果它发现它们相等,它可能会将一些未导出的函数合并在一起,它可能复制或内联其他函数。
尤其是在处理更大的独立“子项目”时,可能会发生这种情况。想象一下,您编写了一个排序函数,然后将其包含在子项目 A 和子项目 B 中,编译/构建所有内容,然后链接并运行。你会以一个或两个排序函数结束吗?在您实际检查并正确调整链接选项之前,这个问题很难回答。
这比数组稍微复杂一些。对于数组,如果数组不同,您会得到不同的指针。这里,同一个函数可能有许多不同的地址。在使用 C++ 中的模板时,这一点可能尤其引人注目,但这又取决于链接器的工作表现。哦,很好的例子:DLL。通过使用基于相似代码的三个 DLL,它们几乎可以保证拥有静态链接到的所有内容的三个副本。
当谈论 DLL 时...您知道它们可以将附加代码加载/卸载到您的内存中,对吧?这意味着当您加载 DLL 时,在某个地址 XYZ 处会出现一个函数。然后你卸载它,它就消失了。但是当你现在加载不同的 DLL 时呢?当然,操作系统可以重用该空间,并且可以将新加载的 DLL 映射到与前一个 DLL 相同的区域。大多数时候你不会注意到它,因为新加载的 DLL 将被映射到不同的区域,但它可能会发生。
这意味着虽然您可以比较指针,但您得到的唯一答案是:指针是否相同?
如果它们不一样,那么你根本不知道;不同的函数指针并不意味着函数不同。可能是这样,99%的情况都是如此,但不一定不同
如果它们相同:
如果您没有多次加载/卸载各种动态库,您可能会认为没有任何变化,并且您可以确定获得了与以前相同的函数/对象/数组
如果您正在使用可卸载的动态模块,您最好根本不要这样假设,除非您完全确定没有任何指针来自将来将被卸载的 DLL。请注意,某些库使用动态库来实现“类似插件”的功能。请小心它们的指针,并注意插件加载/卸载通知。卸载动态库时,您的函数可能会发生变化。
编辑后续内容:
除非您(或您使用的某些库)卸载了DLL,否则您的指向 DLL 目标函数的指针可以安全使用。
一旦加载了 DLL,唯一可以改变该 DLL 所采用的地址含义的邪恶行为就是卸载动态模块。
如果您确定:
那么只要您添加一些安全措施,您的函数指针就可以安全地存储、使用和比较:
如果您怀疑函数指针确实针对动态模块中的函数,该函数将在程序退出之前的某个时间点卸载,并且:
那么你的函数指针根本无法安全使用。我所说的“完全”是指以任何方式“完全”。不要储存它,因为它可能会立即蒸发。