如何在C

时间:2017-02-03 00:03:00

标签: c oop

我想为c函数创建一个包装器,以便我可以将ret = function(arg1,arg2,arg3);形式的函数调用转换为/*void*/ function_wrapper(/*void*/);形式。这类似于C ++和boost bind中的函数对象。

这可能吗?我怎么能这样做?

更新

更详细地解释我在寻找什么:

我们从这个功能开始:

int f(int i){
    //do stuff
    return somevalue;
}

Obvioulsy,它被称为:

// do stuff
int x = 0;
ret = f(0);
// do more stuff.

我想做一些将函数包装到void function(void)

中的魔法
struct function_object fo;
fo.function_pointer = &f;
fo.add_arg(x, int);
fo.set_ret_pointer(&ret);
fo.call();

注意:我看到有人投票支持关闭这个问题并将其标记为不清楚。请不要这样做。我有合理的需要来回答这个问题。如果您需要解释,请询问,我很乐意详细说明。

1 个答案:

答案 0 :(得分:1)

我想出了一个更好的代码,可以让你做你想做的事。首先,我将解释它是如何工作的,展示代码并解释为什么我仍然不认为使用它是个好主意(尽管代码可能为解决这些问题的改进打开了大门)。

功能

  • 在开始使用"函数对象"之前,必须调用初始化函数(FUNCTIONOBJ_initialize();),它将初始化库中使用的每个数据结构的互斥锁。
  • 初始化后,每次要调用其中一个"功能对象"而不使用参数时,必须先进行设置。这是通过创建FUNCTIONOBJ_handler_t指针并调用get_function_handler()来完成的。这将搜索目前可以使用的免费FUNCTIONOBJ_handler数据结构。
  • 如果找不到任何内容(所有FUNCTIONOBJ_handler数据结构都很忙,则会被某些函数调用使用)NULL将被返回。
  • 如果get_function_handler()找到了FUNCTIONOBJ_handler数据结构,它会尝试锁定FUNCTIONOBJ_id_holder数据结构,该数据结构包含ID的{​​{1}}功能即将被召唤
  • 如果FUNCTIONOBJ_handler已被锁定,FUNCTIONOBJ_id_holder将会挂起,直到线程使用它解锁。
  • 锁定get_function_handler()后,会在其上写入抓取的FUNCTIONOBJ_id_holder的ID,FUNCTIONOBJ_handler会返回FUNCTIONOBJ_handler指针。
  • 使用指针,用户可以设置指向参数的指针以及带有get_function_handlerset_args_pointer的返回变量,它们都以set_return_pointer作为参数。
  • 最后,您可以调用所需的功能。它必须:

    1 - 从void *数据结构中抓取FUNCTIONOBJ_handler ID并使用它来获取指向FUNCTIONOBJ_id_holder本身的指针。

    2 - 使用FUNCTIONOBJ_handler访问参数。

    3 - 使用返回函数之一返回(在示例中我们有FUNCTIONOBJ_handler,它将返回一个整数并解锁ret_int

下面是一个简化的思维导图,描述了一些正在发生的事情:

Mind map

最后,代码:

<强> funcobj.h

FUNCTIONOBJ_handler

<强> funcobj.c

#include <stdio.h>
#include <pthread.h>

#define MAX_SIMULTANEOUS_CALLS 1024

typedef struct {
    //Current ID about to be called
    int current_id;

    //Mutex
    pthread_mutex_t id_holder_mutex;
} FUNCTIONOBJ_id_holder_t; 

typedef struct {
    //Attributes
    void *arguments;
    void *return_pointer;

    //Mutex
    pthread_mutex_t handler_mutex;
} FUNCTIONOBJ_handler_t;

FUNCTIONOBJ_handler_t FUNCTIONOBJ_handler[MAX_SIMULTANEOUS_CALLS];
FUNCTIONOBJ_id_holder_t FUNCTIONOBJ_id_holder;

void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void ret_int(FUNCTIONOBJ_handler_t *this, int return_value);
void FUNCTIONOBJ_initialize(void);
FUNCTIONOBJ_handler_t *get_function_handler(void);

<强>的main.c

#include "funcobj.h"

void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
    this->return_pointer = pointer;
}

void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
    this->arguments = pointer;
}

void ret_int(FUNCTIONOBJ_handler_t *this, int return_value){
    if(this->return_pointer){
        *((int *) (this->return_pointer)) = return_value;
    }
    pthread_mutex_unlock(&(this->handler_mutex));
}

void FUNCTIONOBJ_initialize(void){
    for(int i = 0; i < MAX_SIMULTANEOUS_CALLS; ++i){
        pthread_mutex_init(&FUNCTIONOBJ_handler[i].handler_mutex, NULL);
    }

    pthread_mutex_init(&FUNCTIONOBJ_id_holder.id_holder_mutex, NULL);
}

FUNCTIONOBJ_handler_t *get_function_handler(void){
    int i = 0;

    while((0 != pthread_mutex_trylock(&FUNCTIONOBJ_handler[i].handler_mutex)) && (i < MAX_SIMULTANEOUS_CALLS)){
        ++i;
    }
    if(i >= MAX_SIMULTANEOUS_CALLS){
        return NULL;
    }

    //Sets the ID holder to hold this ID until the function is called
    pthread_mutex_lock(&FUNCTIONOBJ_id_holder.id_holder_mutex);
    FUNCTIONOBJ_id_holder.current_id = i;

    return &FUNCTIONOBJ_handler[i];
}

编译:{{1​​}}

避免它的原因:

  • 通过使用它,您将限制&#34;功能对象的数量&#34;可以同时运行。那是因为我们需要使用全局数据结构来保存函数所需的信息(参数和返回指针)。
  • 当使用多个线程时,如果那些使用&#34;功能对象&#34;那么你将严重减慢程序的速度。经常:尽管许多功能可以同时运行,但一次只能设置一个功能对象。因此,至少在程序设置函数并实际调用它所花费的时间内,尝试运行函数的所有其他线程都将等待数据结构解锁。
  • 你仍然需要在你想要工作的每个函数的开头和结尾写一些不直观的代码而不需要参数(抓住#include "funcobj.h" #include <string.h> //Function: void print(void){ //First the function must grab the handler that contains all its attributes: //The FUNCTIONOBJ_id_holder is mutex locked, so we can just access its value and //then free the lock: FUNCTIONOBJ_handler_t *this = &FUNCTIONOBJ_handler[FUNCTIONOBJ_id_holder.current_id]; //We dont need the id_holder anymore, free it! pthread_mutex_unlock(&FUNCTIONOBJ_id_holder.id_holder_mutex); //Do whatever the function has to do printf("%s\n", (char *) this->arguments); //Return the value to the pointed variable using the function that returns an int ret_int(this, 0); } void *thread_entry_point(void *data){ int id = (int) data; char string[100]; snprintf(string, 100, "Thread %u", id); int return_val; FUNCTIONOBJ_handler_t *this; for(int i = 0; i < 200; ++i){ do { this = get_function_handler(); } while(NULL == this); set_args_pointer(this, string); set_return_pointer(this, &return_val); print(); } return NULL; } int main(int argc, char **argv){ //Initialize global data strucutres (set up mutexes) FUNCTIONOBJ_initialize(); //testing with 20 threads pthread_t thread_id[20]; for(int i = 0; i < 20; ++i){ pthread_create(&thread_id[i], NULL, &thread_entry_point, (void *) i); } for(int i = 0; i < 20; ++i){ pthread_join(thread_id[i], NULL); } return 0; } 结构,解锁gcc -o program main.c funcobj.c -lpthread结构,通过你抓住并使用非内置函数返回值的指针)。如果不小心,这会大大增加错误的机会,特别是一些令人讨厌的错误:
  • 增加死锁的几率。如果您忘记在代码的任何一点解锁其中一个数据结构,您最终可能会得到一个在某些时刻工作正常的程序,但随机冻结在其他程序上(因为所有不带参数的函数调用都将等待锁定被释放)。这是在多线程程序上发生的风险,但是通过使用它,您需要增加不必要的锁定代码量(用于样式目的)。
  • 使用递归函数变得复杂:每次调用函数对象时,您都必须经历设置短语(即使在另一个函数对象内部)。此外,如果您调用递归函数足以填满所有FUNCTIONOBJ_handler结构,程序将会死锁
  • 目前我可能没有注意到的其他原因:p