首页 > 技术文章 > C 函数指针

orangeseason 2015-09-11 18:18 原文

Outline:

1. 如何从函数指针获得函数名?

2. 函数指针结构必须与函数同构。

3. 当函数指针作为另一个函数的参数时,另一个函数的该参数不能简单的是指针参数,而应该是整个函数指针定义。这样这个参数才能表面自己是个函数指针,而不是其他普通指针。

 

函数指针可以使状态机编程变得简单,但是同时由于函数指针并不是显示调用函数,在debug程序时可能会增加很多问题。

 

如何从函数指针获得函数名

http://stackoverflow.com/questions/351134/how-to-get-functions-name-from-functions-pointer-in-c

在这个帖子中,大牛们提供了不少方法,

要么需要编译时加参数,这在已成型的编译复杂产品不可用。不过一个提示是在以后debug版本时加上该参数 –rdynamic

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

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

int main(int argc, char *argv[]) {
    void    *funptr = &foo;

    backtrace_symbols_fd(&funptr, 1, 1);

    return 0;
}

Compile with

gcc test.c –rdynamic

output

./a.out

(foo+0x0)[0x8048634]

 

要么在调用函数中直接加log。这个方法最简单,但是最麻烦,当很多函数都被函数指针指向时,可能涉及多个文件多个函数,不仅仅是修改麻烦,更重要的是debug版本控制也会增加额外effort.

 

还有一种方法是使用printk

void *func = &foo;
printk("func: %pF at address: %p\n", func, func);
 
但是这种方法我并没有试验成功.
 
最后,我采用了一种用if实现的简单的map方式,实现指正名查询。好处是可以只修改一个文件便获得函数名。缺点是还是麻烦
#include <stdio.h>
#include <string.h>
int test_fun(char* str) 
{
    printf("test_fun inside: %s\t", str);
    return 1;
}
int ignor_fun(char* str) 
{
    printf("ignor_fun inside: %s\t", str);
    return 1;
}
int getFuncName(int (*funptr)(char* str) , char * funname)   // 函数指针作为参数,该参数必须写完这个函数指针定义int (*funptr)(char* str), 而不是简单是int (*funptr)。 这样编译器才知道该函数是一个函数指针,而非普通变量指正。 
{
    if (funptr == NULL) strcpy(funname, "NULL");
    else if (funptr == test_fun) strcpy(funname, "test_fun"); 
    else strcpy(funname, "UNKNOWN");
    
    if (funptr != NULL) (*funptr)(funname);   //正因为参数里声明是指数参数,才可以做函数调用。
}

int main(int argc, char *argv[]) {
    int    (*funptr)(char* str) ;
    char funname[50] = "UNKNOWN";
    
    printf ("1: %p\t", funptr);
    getFuncName(funptr,funname);    
    printf("find output: %s\n", funname);
     
    funptr = test_fun;
    printf ("2: %p\t", funptr);
    getFuncName(funptr,funname);    
    printf("find output: %s\n", funname);
    
    
    funptr = ignor_fun;
    printf ("3: %p\t", funptr);
    getFuncName(funptr,funname);    
    printf("find output: %s\n", funname);
     
     
    return 1;
}
 
编译并运行

gcc test.c
./a.out
1: (nil)        find output: NULL
2: 0x400504     test_fun inside: test_fun       find output: test_fun
3: 0x400530     ignor_fun inside: UNKNOWN       find output: UNKNOWN

 
在这个例子中,提供一个外部函数 int getFuncName(int (*funptr)(char* str) , char * funname) 查询当前函数名。
 
由于这个外部查询函数中,函数指针是一个函数传入,因此不能同构。

推荐阅读