-3

I would like to call a function (called here just function) that accepts a variable list of arguments without knowing in advance how many arguments will be needed. I have come up with this:

int param_num
char **param // initialized and populated somewhere else
...
if (param_num == 0) result = function();
else if (param_num == 1) result = function(param[0]);
else if (param_num == 2) result = function(param[0],param[1]);
...

The above code is just a proof of concept and is not intended to be compilable. The actual function has at least one fixed argument. I cannot change the function because it belongs to an external library. The actual code is more complex and is working as expected but...

My question is: is there a more compact way of writing the same code without touching "function"?

PS working in Linux with gcc 7

PPS it is just a curiosity. There is no real problem that I am trying to solve. The above code is working as expected. Just wondering if there were a way to make it prettier.

Thanks

  • 1
    How about an `argv` style array? I.e. a null-pointer terminated array of strings (very similar to what you already have) and just pass it to the function (after modifying it to handle such an array of course). And no, there's really no way of making your code "more compact" without touching the function. – Some programmer dude Dec 29 '18 at 10:53
  • I thought about that but I cannot modify the function. Thank you anyway for the comment. – LastStarDust Dec 29 '18 at 10:54
  • Seems like an [XY problem](http://xyproblem.info). Please [edit](https://stackoverflow.com/posts/53968853/edit) your question to motivate it, explain why do you need that (what is your application doing exactly). Your code is not conforming to C (since variadic functions need at least one fixed argument) – Basile Starynkevitch Dec 29 '18 at 11:10
  • 2
    Are you sure the function is as you describe? AFAICS a variadic function must have at least one "fix" parameter. – glglgl Dec 29 '18 at 11:12
  • 1
    Please avoid commenting your own question, but do take some time to [edit](https://stackoverflow.com/posts/53968853/edit) and improve it. Consider adding some [MCVE] in it – Basile Starynkevitch Dec 29 '18 at 11:16
  • 1
    In C, you cannot have the *same* function which is called *without* arguments and with several ones. This is forbidden by the language specification. – Basile Starynkevitch Dec 29 '18 at 11:18
  • 1
    Please explain why are you asking that. Your code is invalid, and cannot even be compiled by a C compiler. I voted to close your question because it is unclear. So please improve it. – Basile Starynkevitch Dec 29 '18 at 11:22
  • 1
    Please explain where is the `function` coming from, and what it does. Why cannot you change it? Take time to give its *exact* declaration in C (the current question has invalid code) – Basile Starynkevitch Dec 29 '18 at 11:29
  • [This](https://stackoverflow.com/questions/12263745/in-c-given-a-variable-list-of-arguments-how-to-build-a-function-call-using-the/12265920)? – Antti Haapala -- Слава Україні Dec 29 '18 at 11:43
  • 1
    I am voting to close this as unclear because... I know it is a duplicate but there is not enough information on which one it is a duplicate of :D – Antti Haapala -- Слава Україні Dec 29 '18 at 11:44
  • @Basile Starynkevitch Yes it is just a XY problem. Please don't overthink it. I would have been satisfied with a simple "no" just as Some programmer dude said. – LastStarDust Dec 29 '18 at 14:39

2 Answers2

3

Read about <stdarg.h> and variadic functions. On Linux, see also stdarg(3). It is how you can define in C such functions of variable arity (like printf). The first few arguments should be fixed, and of known type, so you cannot have exactly what you want (with a call like function() without arguments). So a variadic function is required to have at least one first fixed-type argument (which usually determines, like in printf, the type and number of following variadic arguments). So the C language specification forbids to call the same function without any arguments and with two of them.

Be also aware of the ABI of your system. It defines calling conventions (which usually vary with the signature of the called function) For 64 bits x86 on Linux, see this (floating point and pointer arguments get passed in different registers).

GCC (specifically) has also builtins for constructing function calls, but the C11 standard n1570 don't have anything like that.

It is unclear what you exactly want to achieve, but in some cases you might generate code (e.g. pedantically use metaprogramming) at runtime. There are several ways to achieve that on Linux:

  • You could generate (in a file) some C code in /tmp/emittedcode.c, fork its compilation as a plugin (by running gcc -fPIC -shared -Wall -O -g /tmp/emittedcode.c -o /tmp/generatedplugin.so) then load that plugin using dlopen(3) (as void*dlh = dlopen("/tmp/generatedplugin.so", RTLD_NOW); but you should handle failure) and dlsym(3) of symbols there. My manydl.c example shows that you can practically do that for many hundred thousands of generated plugins.

  • You could use some JIT-compiling library like libgccjit or asmjit or libjit, or GNU lightning, etc...

In both cases, you'll then (conceptually) add a new code segment to your process and get the address of a freshly created function there into some function pointer.

Be also aware of closures and anonymous functions, and notice that C don't have them (but have to use callbacks). Read SICP.

As commented by Antti Haapala, look also into libffi (it enables you to call an arbitrary function with arbitrary arguments by "interpreting" that call, which you would describe by ad-hoc data structures).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • As I said that is not the actual code. Of course, I don't have a function without any fixed arguments at all. But thanks for your insightful answer. I will try to read those references. Anyway, it sounds more complex than I expected and maybe the solution that I used is actually the most simple and compact way to achieve what I need. – LastStarDust Dec 29 '18 at 11:13
  • I am sorry, but your question stays very unclear and needs a lot of improvements. In particular, it lacks motivation and context. Please take a dozen of minutes to [edit](https://stackoverflow.com/posts/53968853/edit) and improve your question (by adding several paragraphs in it). – Basile Starynkevitch Dec 29 '18 at 11:14
  • I am thinking of a way of adding more context without going out of topic but nothing is coming to my mind. Maybe you are overthinking my question ... it is just a simple question. Is it possible to write that code in fewer lines? I was thinking about iterating over the parameter list ... but maybe I am off track. – LastStarDust Dec 29 '18 at 11:20
  • You could iterate over the parameter list (with `va_arg`) but that is only possible for variadic functions which have at least one argument. Your sample code is invalid – Basile Starynkevitch Dec 29 '18 at 11:23
  • 1
    ... and with standard `va_arg` you need to know the type of *each* argument at compile time *somewhere*, the `va_list` cannot be constructed at runtime. – Antti Haapala -- Слава Україні Dec 29 '18 at 13:50
  • Yep, but I won't recommend it. If the OP is generating C code, he should better compile it with an optimizing compiler, which `libtcc` is definitely not. – Basile Starynkevitch Dec 29 '18 at 13:55
0

If you exactly know what type of args you'll need to pass, you can create a structure with possible args defined in it

you can then pass the structure and do your stuff

struct args {
    define args.... 
}
. 
. 
struct args* a;
result = function(a);

keep in mind that you'll have to add some checks in the function to see what args are passed.

Auxilus
  • 217
  • 2
  • 9