确定指针在C中指向哪个函数?
我有一个指向函数的指针,假定有任何签名。我有5个具有相同签名的不同功能。
在运行时,将其中一个分配给指针,然后调用该函数。
在这些函数中不插入任何打印语句,如何知道指针当前指向的函数名?
Sumit asked 2020-01-08T15:11:51Z
9个解决方案
65 votes
您将必须检查指针所指向的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);
nos answered 2020-01-08T15:12:06Z
27 votes
通常,在C语言中,程序员无法使用这些功能。
通过使用调试符号等可能有特定于系统的方法,但是您可能不希望依赖这些方法的存在来使程序正常运行。
但是,您当然可以将指针的值与另一个值进行比较,例如
if (ptr_to_function == some_function)
printf("Function pointer now points to some_function!\n");
janneb answered 2020-01-08T15:12:35Z
16 votes
函数名称在运行时将不可用。
C不是反射性语言。
维护以其名称为键的函数指针表,或者提供一种调用返回该名称的函数的模式。
Bathsheba answered 2020-01-08T15:13:04Z
15 votes
调试器可以告诉您(即函数的名称,给出其地址)。
未剥离的ELF可执行文件的符号表也可能会有所帮助。 参见nm(1),objdump(1),readelf(1)
另一种Linux GNU / libc特定方法可能是在运行时使用dladdr(3)函数。 假设您的程序被很好地动态链接(例如使用dlopen),则它可以找到符号名称和共享对象路径(给定全局函数的地址)。
当然,如果给定签名只有五个功能,则可以将您的地址(与它们的五个地址)进行比较。
请注意,某些函数没有任何((全局可见))名称,例如dlopen函数。
某些功能可能是dlopen-ed和dlsym-ed(例如,在插件内部)。 或者它们的代码在运行时由某些JIT-ing框架合成(libjit、gccjit、LLVM、asmjit)。 而且优化的编译器可以(并且确实可以!)内联函数,克隆它们,尾部调用它们,等等...因此,您的问题通常可能没有任何意义...
另请参阅backtrace(3)和GCC中Ian Taylor的libbacktrace。
但总的来说,您的追求是不可能的。 如果您确实需要可靠的方式提供此类反射性信息,请自己进行管理(以Pitrat的CAIA系统为例,或者以某种方式查看我的MELT系统),也许可以在构建过程中生成一些代码即可。
Basile Starynkevitch answered 2020-01-08T15:13:56Z
13 votes
要知道函数指针指向的位置,您必须对程序进行跟踪。 最常见的是声明一个函数指针数组,并使用一个int变量作为该数组的索引。
话虽如此,如今也可以通过使用__func__标识符在运行时告诉当前正在执行哪个功能:
#include
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
Lundin answered 2020-01-08T15:14:26Z
10 votes
完全没有-函数的符号名称在编译后消失。 与反射语言不同,C并不知道程序员如何命名其语法元素。 特别是,编译后没有按名称进行“函数查找”。
当然,您可以拥有一个功能指针的“数据库”(例如数组),您可以将其与当前指针进行比较。
Marcus Müller answered 2020-01-08T15:14:51Z
8 votes
这是非常糟糕且不可移植的,但假设:
您使用的是Linux或类似的基于ELF的系统。
您正在使用动态链接。
该函数在共享库中,或者您在链接时使用了dladdr。
也许您不应该做出许多其他假设...
您可以通过将函数的地址传递给非标准的dladdr函数来获得函数的名称。
R.. answered 2020-01-08T15:15:34Z
3 votes
设置链接器以输出MAP文件。
暂停程序
检查指针中包含的地址。
在MAP文件中查找地址,以找出要指向的功能。
Mark Ch answered 2020-01-08T15:16:07Z
0 votes
指向C函数的指针是一个地址,就像任何指针一样。 您可以从调试器获取值。 您可以将指针转换为具有足够位数的任意整数类型,以完整地表达它并进行打印。 任何可以使用指针的编译单元,即在范围内具有函数名称,都可以打印指针值或将它们与运行时变量进行比较,而无需触及函数内部的任何内容。
Bill IV answered 2020-01-08T15:16:27Z