C语言根据函数指针得到其函数名

前言

这次遇到的需求是需要知道函数指针指向的函数的名称是什么。感觉是不是有点儿像java里的反射,可以知道运行时的类是啥。

函数指针介绍

  1. 变量名不需要存储,是给人看的,可以参考知乎的这个回答。可以简单理解成编译器编译的时候知道每个变量所储存的地址,在编译完后会把变量替换成值的存储地址。那么,函数也是有存储地址的。
  2. 既然数据变量的内存地址可以存储在相应的指针变量中。函数指针中可以存储函数的首地址,这样就可以通过函数指针变量来调用其指向的函数了。

函数指针的示例代码

函数指针的示例代码,摘自Wikipedia:

# ifndef __cplusplus
    # include <stdio.h>
# else
    # include <cstdio>
# endif

int max(int x, int y)
{
    return x > y ? x : y;
}

int main(void)
{
    /* p 是函数指针 */
    /* 指向具有相同的参数类型,返回类型的函数 */
    int (* p)(int, int) = & max;  // &可以省略
    int a, b, c, d;

    printf("please input 3 numbers:");
    scanf("%d %d %d", & a, & b, & c);

    /* 与直接调用函数等价,d = max(max(a, b), c) */
    d = p(p(a, b), c); 

    printf("the maxumum number is: %d\n", d);

    return 0;
}

代码中,函数名max是一个函数指针常量,而我们定义的函数指针p则是一个函数指针变量

解决方法

回到我们的问题,该如何根据函数指针得到它指向的函数的名称呢?

方法一:内核态、printk()函数

如果是在内核态中,那么可以通过printk()函数来打印出函数名。详情可以参考下网上的Blog。并且需要包含相关的头文件:#include<linux/kernel.h>
或者,如果是在用户态中,那么需要写Makefile,将内核态中的模块编译链接,可以参考下这个链接:linux/module.h: No such file or directory。这个回答里也有人提到用-I加上链接库,但是我没试成功,手动狗头。

方法二:func

在要打印的函数中嵌入以下代码:

printf("%s", __func__);

其中,__func__ 是个标准宏,它能给出当前的函数名。
但是我觉得这样的话,因为我的文件中有很多个函数,而我只能对这些函数的代码进行入侵,添加打印的代码。可以想想有没有什么设计模式可以解决的。

方法三:创建函数指针与函数名对应的字典

创建相关的结构体作为函数地址函数名的字典,在判断的时候进行遍历,看函数指针的地址与函数的地址是否相同,相同的话就可以返回其函数名。
缺点的话就是在创建结构体数组的时候,如果有很多函数的话就得一个一个添加。

示例代码:

typedef void (*simple_fp)();  // 函数指针
typedef struct _function_meta {
    simple_fp func_ptr;
    char * func_name;
} function_meta;  // 函数元数据的结构体,包含函数指针以及函数指针对应的函数名

void f1() {}
void f2() {}
void f3() {}

int main()
{
    void (*unknown_func_pointer)() = f2; // you ignore this
    unknown_func_pointer(); // this is all you see

    printf("f1 %p\n", f1);
    printf("f2 %p\n", f2);
    printf("f3 %p\n", f3);

    printf("unknown_func_pointer %p\n", unknown_func_pointer);

    struct function_meta arrfunc_ptrs[3] = {
	    										{f1, "f1"}, 
	    										{f2, "f2"}, 
	    										{f3, "f3"}
    										};  // 函数元数据数组

    for(int i=0; i<3; i++) 
    {
        if( unknown_func_pointer == arrfunc_ptrs[i].func_ptr )  // 判断要判断的函数指针与函数元数据数组中每个元素的函数指针是否相同
        {
            printf("function name: %s\n", arrfunc_ptrs[i].func_name);  // 是的话则可以打印出其函数名
        }
    }
}

输出如下:

f1 0x40051b
f2 0x400521
f3 0x400527
unknown_func_pointer 0x400521
function name: f2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章