这是事情,我有几个功能,
void foo() {}
void bar() {}
我想像普通物品一样传递这些功能。指针,
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")
}
我可以这样使用这些函数指针吗?我写了一个程序来测试它,似乎没问题。此外,我认为,与stack
或heap
中的普通对象不同,函数位于text segment
(对吗?),所以当我引用foo
时,它给我一个函数foo
位于文本段中的物理地址?
关注
如果我确实使用DLL,请考虑以下事项:首先,为函数ptr fptr
分配一个函数,
ReturnType (*fptr)(ArgType) = beautiful_func;
这里有两个场景,
1)如果beautiful_func不在DLL中,则使用此fptr
是安全的。
2)如果它在DLL中,那么稍后,我认为使用fptr
是不安全的,因为它现在可能指的是一个完全不同的函数,它不是fptr
的诞生,正确?
答案 0 :(得分:3)
你可以通过简单的==它们检查两个函数指针是否相等,因为它们只是普通的指针。这很明显。
然而,当你说'#34;比较"时,请检查你的想法:
比较指针(不仅是函数指针!它适用于所有指针)有点冒险:你没有检查内容(逻辑标识),只检查位置("物理"标识)。大部分时间它都是相同的,但有时候要小心,你会发现副本。
很明显,如果你创建一个数字为1,2,3,4的数组,然后分配另一个数组并将其复制到那里,那么你得到两个不同的指针,对吧?但是阵列对您来说可能是相同的,具体取决于您的需要。
对于函数指针,问题是相同的,甚至更多:你实际上并不知道编译器/链接器对你的代码做了什么。它可能已经优化了一些东西,它可能将一些未导出的函数合并在一起,如果它注意到它们是相同的,它可能已复制或内联其他函数。
特别是在与更大的独立子项目合作时可能会发生这种情况。想象一下,您编写了一个排序函数,然后将其包含在子项目A和子项目B中,编译/构建所有内容,然后链接并运行。你会以一种或两种功能结束吗?在你真正检查并正确定制连接选项之前,这是个难题。
这比使用数组要复杂一些。对于数组,如果数组不同,则会得到不同的指针。这里,相同的功能可以具有许多不同的地址。在C ++中使用模板时,可能特别明显,但这又取决于链接器完成其工作的程度。哦,很好的例子:DLL。有三个基于类似代码的DLL,它们几乎已经保证有三个副本,它们是静态链接的。
当谈论DLL时...你知道他们可以将额外的代码加载/卸载到你的内存中,对吧?这意味着当您加载DLL时,在某个地址XYZ会出现一个函数。然后你卸载它就会消失。但是当你现在加载不同的DLL?当然,允许OS重用该空间,并允许将新加载的DLL映射到与前一个相同的区域。大多数时候你都不会注意到它,因为新加载的DLL将映射到不同的区域,但可能会发生。
这意味着虽然你可以比较指针,但你得到的唯一答案是:指针是否相同?
如果不相同,那么你简单地知道;不同的函数指针不表示函数不同。可能是这样,在99%的情况下会如此,但不一定是不同的
如果相同:
如果您没有多次加载/卸载各种动态库,您可能会认为没有任何变化,您可能确定获得了与以前相同的函数/对象/数组
如果你正在使用无法加载的动态模块,你最好不要假设,除非你绝对确定 none 指针来自将来将被卸载的DLL。请注意,有些库使用动态库来实现"类似插件的"功能。注意它们的指针,并注意插件加载/卸载通知。卸载动态库时,您的功能可能会发生变化。
编辑跟进:
除非你(或你使用的某些库)曾经卸载 DLL,否则你的指向函数的指针-tar-a-DLL是安全的。
加载DLL后,唯一可以改变此DLL所占地址含义的恶意是卸载动态模块。
如果您确定:
然后,只要添加一些安全措施,您的指向函数的指针就可以安全存储,使用和比较:
如果您怀疑指向函数的指针确实以动态模块为目标,该函数将在程序退出之前的某个时间点卸载,并且:
然后你的指向功能不安全就可以使用。至此,我的意思是AT ALL。不要存放它,因为它可能立即蒸发。
答案 1 :(得分:2)
它是否给了我foo函数所在的物理地址 文本段?
除非您正在处理原始操作系统或任何其他特殊操作系统,否则否!
地址不是物理地址,而是virtual addresses!
基本上,操作系统采用的机制允许程序甚至比物理内存更大。因此操作系统负责处理幕后映射。
抱歉,如果我困惑你。 您的理解是正确的(以您使用它们的方式使用函数指针是完全正常的)但地址不是物理地址(指的是主存储器实际寻址的数字)
答案 2 :(得分:2)
是的,C标准允许您将函数指针与运算符==和!=进行比较, 例如来自C11 6.5.9:
当且仅当两者都是空指针时,两个指针才相等 是指向同一对象的指针(包括指向对象的指针) 一个子对象的开头)或功能,
函数所在的确切位置取决于您的平台,它可能位于文本段中,也可能位于其他位置。在virtual memory的操作系统上运行时,地址通常是虚拟地址,而不是物理内存地址。
答案 3 :(得分:1)
考虑到指针存储而非存储器地址的事实,这可以归结为一个数字,是的,你可以比较那种方式。至于从here取得的其他问题,文本段将被定义为“目标文件或内存中包含可执行指令的程序的一个部分。”,这意味着该指针应该包含地址在文本段中的某个地方。
答案 4 :(得分:0)
是的,你可以这样使用。你的理解是正确的。