Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

About wrap and call C function

Tags:

c

closures

lua

ffi

I get this question from this Chinese blog http://chenyufei.info/blog/2011-02-28/wrap-c-function-closure-gcc-nested-function/ The author want to use closure in c language, and he found GCC has the ability of nested function (and closure). For example:

typedef int (*func_t)(int arg);


int foo(int a) {

    return a + 1;

}


func_t create_wrap_function(func_t f) {

    int wrapped(int arg) {

        // call original function

        int val = f(arg);

        fprintf(log_func_call, "arg: %d ret: %d", arg, val);

        return val;
    }

    return wrapped;
}

But it is not common solution. create_wrap_function has fixed function format, because the func_t limits the format.

As we know, Lua has closure, and could call C function too. What I want to implement like: The functions we want to call is foo1 and foo2, they has different types of args and return value.

int foo1(int a) {
    ...
    return intValue;
}

double foo2(char* str, double a) {
   ...
   return dblValue;
}

In C client, call the function like:

lua_returnValue returnValue1 = Do_Lua_Wrap(__FILE__, __LINE__, foo1, 1);
lua_returnValue returnValue2 = Do_Lua_Wrap(__FILE__, __LINE__, foo2, "string data", 1.2345);

In the Do_Lua_Wrap, it will pass the foo1 and 1 to the Lua function, then call foo1 function like normal process. Then pass the foo2 and one char* and one double value to the Lua function, then call foo2 function like normal process. In the Lua function, it could log the information about FILE and LINE and write some extra log about function arguments.

But I don't have idea about how to write the function Do_Lua_Wrap in C and Lua, Is it possible?

If possible, could you give me some advices?

like image 822
sagasw Avatar asked Nov 05 '22 02:11

sagasw


1 Answers

You are obviously interested in a variadic function, but the trouble is determining the type of the arguments to push onto the Lua stack. I'll recommend a couple approaches:

  1. The first would be to include a format string a la the printf family or binary packing formats often used in higher level languages. For example, take a look at the format pattern used in the lpack Lua module. The key is to scan through the format string to determine how many and what kind of arguments are provided.

  2. Alternatively, you could implement a variant type. Each argument would need to be wrapped in such a structure. Also, the total number of arguments would need to be provided as the first parameter.

  3. Finally, you could pass arguments in two arrays instead of using a variadic function. The first array would contain the enumerated types corresponding to the target of void * pointers in the second array. This method requires the most house keeping for client code, but is fairly clean. Either an argument specifying the length of the arrays or a sentinel value at the end of one or both array would be required as well.

Hopefully, one of those methods should work out for you. Personally, I would go with the first option and use the lpack code as a guide. It comes the closest to the function signature specified in your question as well.

like image 113
Judge Maygarden Avatar answered Nov 09 '22 02:11

Judge Maygarden