0

I write a command interpreter that parses a command and its arguments and I would like to find a way to pass them to various non-variadic functions like this:

typedef boolean (*CommandExecuteCallback)(char* arg1, ...);  // n argument variadic function

char command[CMD_WORD_MAXLEN+1];  // currently parsed command
char args[CMD_MAX_ARGUMENTS][CMD_WORD_MAXLEN+1];     // currently parsed arguments

const char *commands[CMD_MAX_COMMANDS];             // available commands
CommandExecuteCallback commandf[CMD_MAX_COMMANDS];  // available execution functions

executeCommand(char *buf)
{
    // find command and parse args
    // call it
    commandf[i](this->args);
}

bool cmd_blink(char* onOff) { ... }
bool cmd_something(char* arg1, char* arg2) { ... }

I am not sure this is possible in C/C++ and definitely not documented here: https://en.cppreference.com/w/cpp/utility/variadic

UPDATE:

Variadic functions cannot be dynamically called in C. The solution is to pass the args as array ´char args[][]´ or as std::vector (std:: is too big for Microcontrollers so the 1st solution prevails) which makes the function signatures match. Thanks JoJo and fabian for the leading hints. I will post the solution below.

RELATED: Forward an invocation of a variadic function in C

cat
  • 2,871
  • 1
  • 23
  • 28
  • 1
    C and C++ are very different languages, there is no such thing as C/C++. It looks like you are using C++. Don't use C-style variadic functions in C++. What do you mean **exactly** by `this->args`? Can you show a declaration of it? – n. m. could be an AI Aug 07 '21 at 07:51
  • `typedef boolean (*CommandExecuteCallback)(char* arg1, ...);` why go with this when you could go with `typedef bool *CommandExecuteCallback(std::vector const& args);`? (also why bool*ean*?) Your `cmd_...` functions btw do not match the signature of the callback in your code; you'd need to write wrapper function that matches the signature and preferrably do parameter count checks. Why make things more compicated than necessary though: If the function gets a `vector` of arguments, it has all the info available without having to deal with the `va_...` stuff. – fabian Aug 07 '21 at 08:02
  • @JeJo You are right it gives a "invalid conversion from ... to ..." so my suspicion is correct, that there is probably no construct in C or C++ that matches dynamic OO Languages like Objective-C. But I have an idea: `typedef boolean (*CommandExecuteCallback)(char* args[])` could work! ad Comment 2: this-> is a leftover of the for this question unrelated OO stuff i failed to remove. – cat Aug 07 '21 at 08:14
  • Thanks. But std:: is no option on Microcontrollers. Its simply too big too soon, so C++ based on normal C Types is the best choice. – cat Aug 07 '21 at 09:31

1 Answers1

0

This is the code I was looking for. Register n-functions with same signature and variable argument lists (all of type char*). Of course this could be enhanced by dynamically managing commands and arguments, but that's not the tricky part and left to the reader. I can't use std:: because it needs to run on an Microcontroller with limited program memory. But other solutions could use std::

typedef boolean (*CommandExecuteCallback)(char args[CMD_MAX_ARGUMENTS][CMD_WORD_MAXLEN+1]);

const char *commands[CMD_MAX_COMMANDS];             // available commands
CommandExecuteCallback commandF[CMD_MAX_COMMANDS];  // available execution functions

char command[CMD_WORD_MAXLEN+1];                    // currently parsed command buffer
char args[CMD_MAX_ARGUMENTS][CMD_WORD_MAXLEN+1];    // currently parsed arguments

interpretCommand()
{
     // parse command and args
     // find i for command
     commandF[i](args); // call the command
}
cat
  • 2,871
  • 1
  • 23
  • 28