确定指针指向C的函数?

时间:2015-10-19 13:12:51

标签: c function-pointers

我有一个指向函数的指针,假设有任何签名。 我有5个不同的功能和相同的签名。

在运行时,其中一个被分配给指针,并调用该函数。

如果不在这些函数中插入任何print语句,我怎样才能知道指针当前指向的函数名称?

9 个答案:

答案 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框架(libjitgccjitLLVMasmjit)合成。并且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)

这非常糟糕且不便携,但假设:

  1. 您使用的是Linux或类似的基于ELF的系统。
  2. 您正在使用动态链接。
  3. 该功能位于共享库中,或者在链接时使用-rdynamic
  4. 你可能不应该做很多其他的假设...
  5. 您可以通过将其地址传递给非标准dladdr函数来获取函数的名称。

答案 7 :(得分:3)

  1. 设置链接器以输出MAP文件。
  2. 暂停程序
  3. 检查指针中包含的地址。
  4. 在MAP文件中查找地址以找出指向的功能。

答案 8 :(得分:0)

指向C函数的指针是一个地址,就像任何指针一样。您可以从调试器获取值。您可以将指针强制转换为具有足够位的任何整数类型以完全表达它,并打印它。任何可以使用指针的编译单元,即在作用域中都有函数名,可以打印指针值或将它们与运行时变量进行比较,而不会触及函数本身内部的任何内容。