如何将函数指针转换为函数名?

时间:2016-11-20 17:03:01

标签: c++

我现在拥有一系列具有相同功能的函数,

func_pointer_t func_array[] = {func_1, func_2, func_3, ...};

我想开发一个遍历所有数组成员的程序,并将输出转储到另一个.dat数据文件。输出应具有以下格式:

func_1 func_1_output
func_2 func_2_output
func_3 func_3_output
...

所以我的问题是 - 当遍历数组成员时,我们怎么能让程序知道函数指针指向哪个函数名(例如func_array [0]指向func_1)?

4 个答案:

答案 0 :(得分:5)

没有标准的存档方式存档。所有可能的解决方案都涉及以系统相关的方式将函数地址解析为其名称(甚至不一定总是有效)或更改func_array如下:

struct {
    func_pointer_t func;
    const char * name;
} func_array[] = {
    { func_1, "func_1" },
    { func_2, "func_2" },
    { func_3, "func_3" },
    ...
};

你可以使用宏来缓解工作:

#define FUNC_DEF(func) { func, #func },

然后像这样使用它:

struct {
    func_pointer_t func;
    const char * name;
} func_array[] = {
    FUNC_DEF(func_1)
    FUNC_DEF(func_2)
    FUNC_DEF(func_3)
    ...
};

所以,如果这是您的选择,那么您就得到了解决方案。如果没有,你必须告诉你,你的目标是什么系统。

存在更多C ++ ish解决方案 - 就像Govind Parmar暗示的std :: map解决方案一样,你可以迭代并获取密钥< - >价值对。

答案 1 :(得分:1)

您可以通过存储与函数指针及其名称匹配的对数组来简单地跟踪名称:

std::pair<const char*, func_pointer_t>[] func_array = {
    {"func_1", func_1},
    {"func_2", func_2},
    {"func_3", func_3}
};

您现在也可以使用它的名字。

你想要,你甚至可以使用地图:

std::map<std::string, func_ptr_t> func_array {
    {"func_1", func_1},
    {"func_2", func_2},
    {"func_3", func_3}
};

答案 2 :(得分:0)

你需要记住,在程序集/机器代码级别没有“函数名称”(除非你的构建中有调试信息);只有地址指示函数的开始位置。

您必须使用数据结构来跟踪这些内容。如果您正在使用C ++,那么请使用map<string, function_pointer>作为评论者@ MyUsername112358指出。

答案 3 :(得分:0)

backtrace_symbols_fd

这不是完美的,但也许它表明了一条道路。改编自How to get function's name from function's pointer in Linux kernel?

main.cpp

#include <execinfo.h>
#include <stdio.h>
#include <unistd.h>

void foo(void) {
    printf("foo\n");
}

int main(int argc, char *argv[]) {
    void *funptr = &foo;
    backtrace_symbols_fd(&funptr, 1, STDOUT_FILENO);
    printf("%p\n", foo);
    return 0;
}

编译并运行:

g++ -std=c++11 main.cpp -rdynamic
./a.out 

输出:

./a.out(_Z3foov+0x0)[0x562ff384893a]
0x562ff384893a

因此,我们看到输出了foo的错误名称_Z3foov

echo _Z3foov | c++filt

我不知道如何解决的缺点是:

  • 需要使用-rdynamic修改内部版本,因​​此不适用于静态链接,并且可能还有其他缺点
  • 不会自动脱粒

但是我确实认为研究回溯机制是一个不错的选择,我已经在print call stack in C or C++

进行了进一步研究。

也许我们也可以摆脱调试信息:Programmatically get debug information可能实际上是最稳定的方法。但是目前没人知道怎么做。

在Ubuntu 18.04,GCC 7.4.0中进行了测试。