Chinaunix首页 | 论坛 | 博客
  • 博客访问: 503291
  • 博文数量: 35
  • 博客积分: 3472
  • 博客等级: 中校
  • 技术积分: 935
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-04 06:54
文章分类
文章存档

2014年(4)

2013年(2)

2011年(3)

2010年(9)

2009年(9)

2008年(8)

分类:

2009-03-05 10:33:21


在运行时动态绑定函数调用是一种经常使用的方法,可以用来解除静态绑定的紧耦合,在java等语言中可以使用反射功能来实现(Method.invoke()),在c/c++中比较常用的是使用dlopen和dlsym动态查找需要的函数指针,然后直接调用。但是这需要事先知道这个函数需要哪些参数,然后才能使用。

也许我们需要这样的能力,一些服务提供了对外的函数接口,并把这些接口的描述保存在一个配置文件中,包括函数的名字,参数个数,参数类型,以及返回值,另外有一个客户程序来访问这些服务,在读取了配置文件之后,客户程序就可以通过用户的输入或者其他环境参数来构造对函数接口的调用。听起来很像WebService的开发库的功能,的确是这样,只不过这里开发语言是c/c++,不通过http协议,而是直接在进程空间中调用。

因为在c/c++中,函数调用是由编译器完成的,语言本身并不提供对函数调用栈的访问,但是gcc提供了这样的扩展接口,__builtin_apply_args(), __builtin_apply()和__builtin_return()是完成这个功能的主要函数,当然gcc的其他扩展可以让我们做更多的事情,但是这里已经足够了。


#include <stdio.h>
#include <string.h>

typedef struct {
    char * first_name;
    char * last_name;
} selName;
static char name_buf[128];

static char command_result[128];

int add(int a, int b) {
    printf("adding: [%d, %d]\n", a, b);
    return b-a;
}

int multiple(int a, int b) {
    printf("multi: [%d, %d]\n", a, b);
    return b*a;
}

char * echo(selName * name) {
    printf("echo: [%s, %s]\n", name->first_name, name->last_name);
    memset(name_buf, 0, 128);
    sprintf(name_buf, "%s %s", name->first_name, name->last_name);
    return name_buf;
}

void * passthrough(int a, int b)
{
    void (*fn)() = (void (*)()) add;

    void *record = __builtin_apply_args();
    int args[128];
    args[0] = a;
    args[1] = b;
    int *p = (int*)record;
    int *p1 = (int*) p[0];
    int *p2 = (int*) p[0];
    printf("params: [%d, %d]\n", p[0], p[1]);

    void * playback = __builtin_apply( (void (*)(...))fn, record, 128);
    p = (int*)playback;
    p1 = (int*) p[0];
    printf("params: [%d]\n", p[0]);
    //printf("after calling [%d, %d]\n", (int)playback, *((int*)playback));

    //__builtin_return(playback);

    return playback;
}

void * callFunc(void * args, void * fn)
{
    void * playback = __builtin_apply( (void (*)(...))fn, args, 128);
    int * p = (int*)playback;
    int * p1 = (int*) p[0];
    printf("params: [%d]\n", p[0]);
    //__builtin_return(playback);

    return playback;
}


char * handleCommand(char * command)
{
    static int arg_buf[128];
    static int* arg_obj[1];
    arg_obj[0] = (int*) arg_buf;
    void * result;
    void * args = &arg_obj;
    if (strncmp(command, "add", 3) == 0) {
        int a;
        int b;
        sscanf(command, "add %d %d", &a, &b);
        arg_buf[0] = a;
        arg_buf[1] = b;
        void (*fn)() = (void (*)()) add;
        void *result = callFunc((void*)args, (void*)fn);
        
        memset(command_result, 0, 128);
        int * p = (int*)result;
        sprintf(command_result, "%d", p[0]);
    }
    else if (strncmp(command, "mul", 3) == 0) {
        int a;
        int b;
        sscanf(command, "mul %d %d", &a, &b);
        arg_buf[0] = a;
        arg_buf[1] = b;
        void (*fn)() = (void (*)()) multiple;
        void *result = callFunc((void*)args, (void*)fn);

        memset(command_result, 0, 128);
        int * p = (int*)result;
        sprintf(command_result, "%d", p[0]);

    }
    else if (strncmp(command, "echo", 4) == 0) {
        selName tmp;
        char first_name[16];
        char last_name[16];
        memset(first_name, 0, 16);
        memset(last_name, 0, 16);
        strncpy(first_name, command+5, 5);
        strncpy(last_name, command+11, 2);
        printf("param: %s %s", first_name, last_name);
        tmp.first_name = first_name;
        tmp.last_name = last_name;
        arg_buf[0] = (int) &tmp;
        void (*fn)() = (void (*)()) echo;
        void *result = callFunc((void*)args, (void*)fn);

        memset(command_result, 0, 128);
        char ** p = (char**)result;
        char *res = *p;
        sprintf(command_result, "%s", res);
    }

    return command_result;
}



int main()
{
//    void * p = passthrough(12, 23);

//    printf("value: %d\n", *((int*)p));


    char * res = handleCommand("add 3 5");
    printf("result: [%s]\n", res);
    res = handleCommand("echo harry he");
    printf("result: [%s]\n", res);
}





阅读(2022) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~