我有一个指向函数的指针,假设有任何签名。 我有5个不同的功能和相同的签名。
在运行时,其中一个被分配给指针,并调用该函数。
如果不在这些函数中插入任何print语句,我怎样才能知道指针当前指向的函数名称?
答案 0 :(得分:65)
您必须检查指针指向的5个函数中的哪一个:
if (func_ptr == my_function1) {
puts("func_ptr points to my_function1");
} else if (func_ptr == my_function2) {
puts("func_ptr points to my_function2");
} else if (func_ptr == my_function3) {
puts("func_ptr points to my_function3");
} ...
如果这是您需要的常见模式,则使用结构表而不是函数指针:
typedef void (*my_func)(int);
struct Function {
my_func func;
const char *func_name;
};
#define FUNC_ENTRY(function) {function, #function}
const Function func_table[] = {
FUNC_ENTRY(function1),
FUNC_ENTRY(function2),
FUNC_ENTRY(function3),
FUNC_ENTRY(function4),
FUNC_ENTRY(function5)
}
struct Function *func = &func_table[3]; //instead of func_ptr = function4;
printf("Calling function %s\n", func->func_name);
func ->func(44); //instead of func_ptr(44);
答案 1 :(得分:27)
通常,在C中,程序员无法使用这些东西。
可能有一些特定于系统的方法可以通过使用调试符号等来实现,但您可能不希望依赖这些方法来使程序正常运行。
但是,您当然可以将指针的值与另一个值进行比较,例如
if (ptr_to_function == some_function)
printf("Function pointer now points to some_function!\n");
答案 2 :(得分:16)
函数名称在运行时将不可用。
C不是反射语言。
维护一个由其名称键入的函数指针表,或者提供一个调用模式的每个返回名称的函数。
答案 3 :(得分:15)
调试器可以告诉你(即函数的名称,给定它的地址)。
未提取的ELF可执行文件的符号表也可以提供帮助。请参阅nm(1),objdump(1),readelf(1)
另一种Linux GNU / libc特定方法可以在运行时使用dladdr(3)函数。假设你的程序很好地动态链接(例如与-rdynamic
),它可以找到符号名称和共享对象路径给定一些地址(全局命名的函数)。
当然,如果您只有给定签名的五个功能,您可以比较您的地址(到它们的五个地址)。
请注意,某些功能没有任何((全局可见)名称,例如static
个功能。
有些功能可能是dlopen
- ed和dlsym
- ed(例如插件内部)。或者他们的代码在运行时由一些JIT框架(libjit
,gccjit
,LLVM
,asmjit
)合成。并且optimizing compiler可以(并且确实!)内联函数,克隆它们,tail-call它们等等......所以你的问题一般没有任何意义......
另见backtrace(3)& Ian Taylor在GCC内部libbacktrace。
但总的来说,你的追求是不可能的。如果您确实需要以可靠的方式提供此类反馈信息,请自行管理(以Pitrat's CAIA系统为例,或以某种方式查看我的MELT系统),或许可以在构建期间生成一些代码。
答案 4 :(得分:13)
要知道函数指针指向的位置,您必须跟踪程序。最常见的是声明一个函数指针数组,并使用int变量作为此数组的索引。
话虽如此,现在也可以通过使用__func__
标识符在运行时告诉当前执行哪个函数:
#include <stdio.h>
typedef const char* func_t (void);
const char* foo (void)
{
// do foo stuff
return __func__;
}
const char* bar (void)
{
// do bar stuff
return __func__;
}
int main (void)
{
func_t* fptr;
fptr = foo;
printf("%s executed\n", fptr());
fptr = bar;
printf("%s executed\n", fptr());
return 0;
}
输出:
foo executed
bar executed
答案 5 :(得分:10)
完全没有 - 编译后函数的符号名称消失。与反射语言不同,C不知道程序员如何命名其语法元素;特别是,编译后没有名称的“函数查找”。
你当然可以拥有一个函数指针的“数据库”(例如数组),你可以将当前指针与之比较。
答案 6 :(得分:8)
这非常糟糕且不便携,但假设:
-rdynamic
。您可以通过将其地址传递给非标准dladdr
函数来获取函数的名称。
答案 7 :(得分:3)
答案 8 :(得分:0)
指向C函数的指针是一个地址,就像任何指针一样。您可以从调试器获取值。您可以将指针强制转换为具有足够位的任何整数类型以完全表达它,并打印它。任何可以使用指针的编译单元,即在作用域中都有函数名,可以打印指针值或将它们与运行时变量进行比较,而不会触及函数本身内部的任何内容。