Related
I'm relatively new to c++, mostly worked with python.
I have a scenario where a user(me) uses a GUI to send commands to a microcontroller via serial, and then the microcontroller processes them.
Right now i have 10 commands, but as the project develops (some form of modular robot) I can envision having 50-100 possible commands.
Is there a better way for my c++ handleCommands function to select which one of the possible 100 functions to run without doing massive case switches or if else statements?
Extract of the code:
char cmd = 1; // example place holder
int value = 10; //example place holder
switch (cmd){
case '1':
toggleBlink(value);
break;
case '2':
getID(value); // in this case value gets ignored by the function as its not required
break;
This works fine for 3-4 functions but doesn't seem to me like the best way to do it for more functions.
I've heard of lookup tables but as each function is different and may require arguments or not I'm consumed on how to implement them.
Some background on the set-up:
The commands are mainly diagnostic ,< ID > ect and a couple of functional ones that require parameters like, <blink,10> <runto,90> <set-mode,locked>
The validation is done in python against a csv file and the actual serial message sent to the microcontroller is sent as <(index of comand in csvfile),parameter> with < > and , being delimiters.
So the user would type blink,10 and the python app will send <1,10> over serial as blink is found at index 1 of the csv file.
The microcontroller reads these in and i am left over with 2 char arrays, the command array containing a number, and the value array containing the value sent.(also a number)
As I'm running this on a microcontroller i don't really want to have to store a long file of possible commands in flash, hence the validation done on the python gui side.
Note that in the case of a possible multi argument function, say <move,90,30> i.e move 90 degrees in 30 seconds eat, the actual function would only receive one argument "30,90" and then split that up as needed.
If you have the commands comming over the serial line in the format
<command-mapped-to-a-number,...comma-separated-parameters...>
we can simulate that like so:
#include <iostream>
#include <sstream> // needed for simple parsing
#include <string>
#include <unordered_map> // needed for mapping of commands to functors
int main() {
std::cout << std::boolalpha;
// example commands lines read from serial:
for (auto& cmdline : {"<1,10>", "<2,10,90>", "<3,locked>", "<4>"}) {
std::cout << exec(cmdline) << '\n';
}
}
exec above is the interpreter that will return true if the command line was parsed and executed ok. In the examples above, command 1 takes one parameter, 2 takes two, 3 takes one (string) and 4 doesn't have a parameter.
The mapping from command-mapped-to-a-number could be an enum:
// uint8_t has room for 256 commands, make it uint16_t to get room for 65536 commands
enum class command_t : uint8_t {
blink = 1,
take_two = 2,
set_mode = 3,
no_param = 4,
};
and exec would make the most basic validation of the command line (checking < and >) and put it in a std::istringstream for easy extraction of the information on this command line:
bool exec(const std::string& cmdline) {
if(cmdline.size() < 2 || cmdline.front() != '<' || cmdline.back() != '>' )
return false;
// put all but `<` and `>` in an istringstream:
std::istringstream is(cmdline.substr(1,cmdline.size()-2));
// extract the command number
if (int cmd; is >> cmd) {
// look-up the command number in an `unordered_map` that is mapped to a functor
// that takes a reference to an `istringstream` as an argument:
if (auto cit = commands.find(command_t(cmd)); cit != commands.end()) {
// call the correct functor with the rest of the command line
// so that it can extract, validate and use the arguments:
return cit->second(is);
}
return false; // command look-up failed
}
return false; // command number extraction failed
}
The only tricky part left is the unordered_map of commands and functors.
Here's a start:
// a helper to eat commas from the command line
struct comma_eater {} comma;
std::istream& operator>>(std::istream& is, const comma_eater&) {
// next character must be a comma or else the istream's failbit is set
if(is.peek() == ',') is.ignore();
else is.setstate(std::ios::failbit);
return is;
}
std::unordered_map<command_t, bool (*)(std::istringstream&)> commands{
{command_t::blink,
[](std::istringstream& is) {
if (int i; is >> comma >> i && is.eof()) {
std::cout << "<blink," << i << "> ";
return true;
}
return false;
}},
{command_t::take_two,
[](std::istringstream& is) {
if (int a, b; is >> comma >> a >> comma >> b && is.eof()) {
std::cout << "<take-two," << a << ',' << b << "> ";
return true;
}
return false;
}},
{command_t::set_mode,
[](std::istringstream& is) {
if (std::string mode; is >> comma && std::getline(is, mode,',') && is.eof()) {
std::cout << "<set-mode," << mode << "> ";
return true;
}
return false;
}},
{command_t::no_param,
[](std::istringstream& is) {
if (is.eof()) {
std::cout << "<no-param> ";
return true;
}
return false;
}},
};
If you put that together you'll get the below output from the successful parsing (and execution) of all command lines received:
<blink,10> true
<take-two,10,90> true
<set-mode,locked> true
<no-param> true
Here's a live demo.
Given an integer index for each "command" a simple function pointer look-up table can be used. For example:
#include <cstdio>
namespace
{
// Command functions (dummy examples)
int examleCmdFunctionNoArgs() ;
int examleCmdFunction1Arg( int arg1 ) ;
int examleCmdFunction2Args( int arg1, int arg2 ) ;
int examleCmdFunction3Args( int arg1, int arg2, arg3 ) ;
int examleCmdFunction4Args( int arg1, int arg2, int arg3, int arg4 ) ;
const int MAX_ARGS = 4 ;
const int MAX_CMD_LEN = 32 ;
typedef int (*tCmdFn)( int, int, int, int ) ;
// Symbol table
#define CMD( f ) reinterpret_cast<tCmdFn>(f)
static const tCmdFn cmd_lookup[] =
{
0, // Invalid command
CMD( examleCmdFunctionNoArgs ),
CMD( examleCmdFunction1Arg ),
CMD( examleCmdFunction2Args ),
CMD( examleCmdFunction3Args ),
CMD( examleCmdFunction4Args )
} ;
}
namespace cmd
{
// For commands of the form: "<cmd_index[,arg1[,arg2[,arg3[,arg4]]]]>"
// i.e an angle bracketed comma-delimited sequence commprising a command
// index followed by zero or morearguments.
// e.g.: "<1,123,456,0>"
int execute( const char* command )
{
int ret = 0 ;
int argv[MAX_ARGS] = {0} ;
int cmd_index = 0 ;
int tokens = std::sscanf( "<%d,%d,%d,%d,%d>", command, &cmd_index, &argv[0], &argv[1], &argv[2], &argv[3] ) ;
if( tokens > 0 && cmd_index < sizeof(cmd_lookup) / sizeof(*cmd_lookup) )
{
if( cmd_index > 0 )
{
ret = cmd_lookup[cmd_index]( argv[0], argv[1], argv[2], argv[3] ) ;
}
}
return ret ;
}
}
The command execution passes four arguments (you can expand that as necessary) but for command functions taking fewer arguments they will simply be "dummy" arguments that will be ignored.
Your proposed translation to an index is somewhat error prone and maintenance heavy since it requires you to maintain both the PC application symbol table and the embedded look up table in sync. It may not be prohibitive to have the symbol table on the embedded target; for example:
#include <cstdio>
#include <cstring>
namespace
{
// Command functions (dummy examples)
int examleCmdFunctionNoArgs() ;
int examleCmdFunction1Arg( int arg1 ) ;
int examleCmdFunction2Args( int arg1, int arg2 ) ;
int examleCmdFunction3Args( int arg1, int arg2, arg3 ) ;
int examleCmdFunction4Args( int arg1, int arg2, int arg3, int arg4 ) ;
const int MAX_ARGS = 4 ;
const int MAX_CMD_LEN = 32 ;
typedef int (*tCmdFn)( int, int, int, int ) ;
// Symbol table
#define SYM( c, f ) {#c, reinterpret_cast<tCmdFn>(f)}
static const struct
{
const char* symbol ;
const tCmdFn command ;
} symbol_table[] =
{
SYM( cmd0, examleCmdFunctionNoArgs ),
SYM( cmd1, examleCmdFunction1Arg ),
SYM( cmd2, examleCmdFunction2Args ),
SYM( cmd3, examleCmdFunction3Args ),
SYM( cmd4, examleCmdFunction4Args )
} ;
}
namespace cmd
{
// For commands of the form: "cmd[ arg1[, arg2[, arg3[, arg4]]]]"
// i.e a command string followed by zero or more comma-delimited arguments
// e.g.: "cmd3 123, 456, 0"
int execute( const char* command_line )
{
int ret = 0 ;
int argv[MAX_ARGS] = {0} ;
char cmd[MAX_CMD_LEN + 1] ;
int tokens = std::sscanf( "%s %d,%d,%d,%d", command_line, cmd, &argv[0], &argv[1], &argv[2], &argv[3] ) ;
if( tokens > 0 )
{
bool cmd_found = false ;
for( int i = 0;
!cmd_found && i < sizeof(symbol_table) / sizeof(*symbol_table);
i++ )
{
cmd_found = std::strcmp( cmd, symbol_table[i].symbol ) == 0 ;
if( cmd_found )
{
ret = symbol_table[i].command( argv[0], argv[1], argv[2], argv[3] ) ;
}
}
}
return ret ;
}
}
For very large symbol tables you might want a more sophisticated look-up, but depending on the required performance and determinism, the simple exhaustive search will be sufficient - far faster than the time taken to send the serial data.
Whilst the resource requirement for the symbol table is somewhat higher that the indexed look-up, it is nonetheless ROM-able and will can be be located in Flash memory which on most MCUs is a less scarce resource than SRAM. Being static const the linker/compiler will most likely place the tables in ROM without any specific directive - though you should check the link map or the toolchain documentation n this.
In both cases I have defined the command functions and executer as returning an int. That is optional of course, but you might use that for returning responses to the PC issuing the serial command.
What you are talking about are remote procedure calls. So you need to have some mechanism to serialize and un-serialize the calls.
As mentioned in the comments you can make a map from cmd to the function implementing the command. Or simply an array. But the problem remains that different functions will want different arguments.
So my suggestion would be to add a wrapper function using vardiac templates.
Prefix every command with the length of data for the command so the receiver can read a block of data for the command and knows when to dispatch it to a function. The wrapper then takes the block of data, splits it into the right size for each argument and converts it and then calls the read function.
Now you can make a map or array of those wrapper function, each one bound to one command and the compiler will generate the un-serialize code for you from the types. (You still have to do it once for each type, the compiler only combines those for the full function call).
I'm having fun coding simple OpenGL demos and I recently decided to use Lua with my C++ engine in order to change the rendering dynamically without having to recompile on and on my project. Thus I can tweak more easily the rendering algorithm. But I know that my current rendering update functions are probably far from being efficient.
For the moment, I'm transfering a matrix from C++ to Lua, modifying it in a Lua script and sending it back to my C++ rendering engine. But I'm reloading the Lua script each time I get an update call from the C++ engine, and I'm losing all of the variable context. That means I'm always starting from scratch and my rendering is far from being smooth. I include some code sample below to explain what I'm doing. I am currently learning Lua with C++ embedding, so I know I still don't have the best practices.
update.lua
function transform(m)
amplitude = 1.5
frequency = 500
phase = 0.0
r = {}
for i = 1, #m do
r[i] = {}
for j = 1, #m[i] do
if (i % 2) then
r[i][j] = amplitude * math.sin(m[i][j] + phase)
else
r[i][j] = -amplitude * math.sin(m[i][j] + phase)
end
phase = phase + 0.001
end
end
return r
end
-- called by c++
function update()
m = pull()
r = transform(m)
push(r)
end
matrix.cpp
// pull matrix from lua point of view
static int pull(lua_State * _L)
{
_push(_L, &_m);
return 1;
}
// push matrix from lua point of view
static int push(lua_State * _L)
{
// get number of arguments
int n = lua_gettop(_L);
if(1 == n) {
_pull(_L, 1, &_m);
}
return 1;
}
void matrix::load_file(char * file, char * function)
{
int status;
// load the file containing the script we are going to run
status = luaL_loadfile(_L, file);
switch (status) {
case LUA_OK:
break;
case LUA_ERRFILE:
std::cout << "LUA_ERRFILE: " << lua_error(_L) << std::endl;
break;
case LUA_ERRSYNTAX:
std::cout << "LUA_ERRSYNTAX: " << lua_error(_L) << std::endl;
break;
default:
std::cout << lua_error(_L) << std::endl;
}
lua_getglobal(_L, function);
status = lua_pcall(_L, 1, 1, 0);
if (status != LUA_OK) {
std::cout << "error running file" << lua_error(_L) << std::endl;
}
}
void matrix::update()
{
load_file("lua/update.lua", "update");
}
I'm thinking of passing some arguments when calling the update() function, but I'm wondering if the C++ to Lua then back to C++ approach is correct and efficient. Especially considering the fact that I might transfer and modify huge matrix in Lua. I probably lack some embedded Lua knowledge to keep context while loading a script. Do you have some general advice on how I would improve my code ? I know that my current approach is overly complicated.
A quick fix would be to only load the file if it has been modified since the last frame:
static time_t last_modified = 0;
struct stat sbuf;
stat(file, &sbuf);
if (sbuf.st_mtime > last_modified) {
last_modified = sbuf.st_mtime;
status = luaL_loadfile(_L, file);
// etc
}
// Now call the function
lua_getglobal(_L, function);
status = lua_pcall(_L, 1, 1, 0);
OK, loading the chunk of the update() function into a global variable and having a global parameter table in the Lua script is the way to go. I achieved this using the following guidelines, and I will post the detailed steps below. Basically, loading the script entirely first ensures that all global variables are stored in the C++ context. Then storing the wanted function as an index allows us to run it again, while keeping the global variables in the script evolving on their own.
Step 1
First call luaL_loadfile once at init
Step 2
Run the script once using lua_pcall(_L, 0, 0, 0);
This ensures that the global variables, which are used as parameters in the Lua script are in memory.
Step 3
Store the Lua function. I managed to do it with the following C++ code:
void matrix::store(char * function)
{
lua_newtable(_L); // create table for functions
_idx = luaL_ref(_L, LUA_REGISTRYINDEX); // store said table in pseudo-registry
lua_rawgeti(_L, LUA_REGISTRYINDEX, _idx); // retrieve table for functions
lua_getglobal(_L, function); // retrieve function to store
if (lua_isfunction(_L, -1)) {
_f = luaL_ref(_L, -2); // store a function in the function table
}
else {
lua_pop(_L, 1);
std::cout << "can't find " << function << std::endl;
}
// table is two places up the current stack counter
lua_pop(_L, 1); // we are done with the function table, so pop it
std::cout << "idx: " << _idx << ", function: " << _f << std::endl;
}
Step 4
Call the stored function again when rendering using the following C++ function:
void matrix::run()
{
int status;
if (_f == -1) {
std::cout << "invalid function index " << _f << std::endl;
}
else {
lua_rawgeti(_L, LUA_REGISTRYINDEX, _idx); // retrieve function table
lua_rawgeti(_L, -1, _f); // retrieve function
//use function
status = lua_pcall(_L, 0, 0, 0); // 0 arguments, 0 results
if (status != LUA_OK) {
std::cout << "error running function" << lua_error(_L) << std::endl;
}
//don't forget to pop the function table from the stack
lua_pop(_L, 1);
}
}
Step 5 (optional)
If we set all the Lua parameters in a global table, we can retrieve them dynamically in C++ using the following piece of code:
void matrix::get_params(char * p)
{
lua_getglobal(_L, p);
lua_pushnil(_L);
int i = 0;
while(lua_next(_L,-2))
{
const char * key = lua_tostring(_L,-2);
double value = lua_tonumber(_L,-1);
lua_pop(_L,1);
std::cout << key << " = " << value << std::endl;
_h[i].key.assign(key);
_h[i].value = value;
i++;
}
lua_pop(_L, 1);
}
Where _his a simple dynamic structure defined as such:
typedef struct {
std::string key;
float value;
} hash;
I only use float, so this simple structure is convenient enough for my needs, and allows me to add lots of variables in my Lua script without bothering with a structure definition in C++. This way I can add as many parameters in my Lua table and do the maths when updating.
Step 6
Tweak the Lua script forever ! Et voila:
p = {
amplitude = 1.5,
frequency = 500,
phase = 0.0
}
function transform(m)
r = {}
for i = 1, #m do
r[i] = {}
for j = 1, #m[i] do
if (i % 2) then
r[i][j] = p.amplitude * math.sin(m[i][j] + p.phase)
else
r[i][j] = -p.amplitude * math.sin(m[i][j] + p.phase)
end
p.phase = p.phase + 0.001
end
end
return r
end
-- called by c++
function update()
m = pull()
r = transform(m)
push(r)
end
This solution fits my needs, but seems very complicated and inefficient. But it was a fine hacking session anyway.
I am trying to use Lua for the configuration of a C++ application and am having trouble generating helpful messages when something is wrong in the configuration, not the the Lua syntax.
For example, suppose the following is a valid configuration:
foo = { a = 0, b = 'bar' }
but the user actually typed this:
foo = { a = 0, c = 'bar' }
Now, the app knows that foo can have fields a and b. It can load foo and get the value of a. It can even tell that b is not set and use a default. But I want to detect that c is present and report a warning.
Here is an extract of my attempt at that which blows up:
static void check_table(lua_State* L)
{
lua_pushnil(L);
while ( lua_next(L, -2) )
{
// key at -2 and value at -1
if ( lua_isstring(L, -2) )
{
const char* key = lua_tostring(L, -2);
// validate here; just printing key for now
cout << key << endl;
}
lua_pop(L, 1);
}
}
This works fine as long as the table is not actually an array. When I hit one of those, it dies on the second iteration with this:
...
1
PANIC: unprotected error in call to Lua API (invalid key to 'next')
which I attribute to this from the Lua reference page:
"If the value is a number, then lua_tolstring also changes the actual value in the
stack to a string. (This change confuses lua_next when lua_tolstring is applied to
keys during a table traversal.)"
Any way around this? I am open to alternate approaches. Ideally a message could be emitted like:
WARNING: conf.lua line 18: table foo does not use key 'c', ignored
(The Lua debug API doesn't give the file name and line number either, but that is a different topic.)
PS: I know, c could benign, but it could also be a typo. In a large configuration, ignoring such things could lead to hours of head scratching.
Validation will probably be much easier if written in Lua. I have something like this in mind:
local template = { a="number", b="string"}
local function validate(t)
for k,v in pairs(t) do
if template[k]==nil then
print("field "..k.." cannot be present")
elseif type(v)~=template[k] then
print("field "..k.." should be a "..template[k])
end
end
end
validate{ a = 0, b = 'bar' }
validate{ a = 0, b = 42 }
validate{ a = 0 }
validate{ a = 0, c = 'bar' }
lua_isstring is defined:
LUA_API int lua_isstring (lua_State *L, int idx) {
int t = lua_type(L, idx);
return (t == LUA_TSTRING || t == LUA_TNUMBER);
}
So instead of:
if ( lua_isstring(L, -2) )
use:
if ( lua_type(L, -2) == LUA_TSTRING )
To parse function parameters I get from JavaScript, I need to perform a lot of checks. For example a function might expect an object as parameter that looks like this in JavaScript.
{
Fullscreen: [ 'bool', false ],
Size: [ 'Vector2u', 800, 600 ],
Title: [ 'string', 'Hello World' ],
// more properties...
}
In C++ I parse this by looping over all keys and check them. If one of those checks fail, an error message should be printed and this key value pair should be skipped. This is how my implementation looks at the moment. I hope you doesn't get distracted from some of the engine specific calls.
ModuleSettings *module = (ModuleSettings*)HelperScript::Unwrap(args.Data());
if(args.Length() < 1 || !args[0]->IsObject())
return v8::Undefined();
v8::Handle<v8::Object> object = args[0]->ToObject();
auto stg = module->Global->Get<Settings>("settings");
v8::Handle<v8::Array> keys = object->GetPropertyNames();
for(unsigned int i = 0; i < keys->Length(); ++i)
{
string key = *v8::String::Utf8Value(keys->Get(i));
if(!object->Get(v8::String::New(key.c_str()))->IsArray())
{
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
}
v8::Handle<v8::Array> values = v8::Handle<v8::Array>::Cast(object->Get(v8::String::New(key.c_str())));
if(!values->Has(0) || !values->Get(0)->IsString())
{
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
}
string type = *v8::String::Utf8Value(values->Get(0));
if(type == "bool")
{
if(!values->Has(1) || !values->Get(1)->IsBoolean())
{
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
}
stg->Set<bool>(key, values->Get(1)->BooleanValue());
}
else if(type == "Vector2u")
{
if(!values->Has(1) || !values->Has(2) || !values->Get(1)->IsUint32(), !values->Get(2)->IsUint32())
{
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
}
stg->Set<Vector2u>(key, Vector2u(values->Get(1)->Uint32Value(), values->Get(2)->Uint32Value()));
}
else if(type == "string")
{
if(!values->Has(1) || !values->Get(1)->IsString())
{
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
}
stg->Set<string>(key, *v8::String::Utf8Value(values->Get(1)));
}
}
As you can see, I defined when happens when a check fails at every filter.
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;
I would like to only write that once, but I can only come up with a way using goto which I would like to prevent. Is there a better option to restructure the if else construct?
I think I'd start with a set of small classes to do the verification step for each type:
auto v_string = [](v8::Handle<v8::Array> const &v) {
return v->Has(1) && v->Get(1)->IsString();
}
auto v_Vector2u = [](v8::Handle<v8::Array> const &v) {
return v->Has(1) && v->Has(2) &&
v->Get(1)->IsUint32() && v->Get(2)->IsUint32();
}
// ...
Then I'd create a map from the name of a type to the verifier for that type:
std::map<std::string, decltyp(v_string)> verifiers;
verifiers["string"] = v_string;
verifiers["Vector2u"] = v_Vector2u;
// ...
Then to verify a type, you'd use something like this:
// find the verifier for this type:
auto verifier = verifiers.find(type);
// If we can't find a verifier, reject the data:
if (verifier == verifiers.end())
HelperDebug::Fail("script", "unknown type: " + type);
// found the verifier -- verify the data:
if (!verifier->second(values))
HelperDebug::Fail("script", "could not parse (" + key + ") setting");
A pretty usual way for such situations is to use a macro. That is #defined before or in the funciton and #undef-ed at function end. As you need continue there, the other ways are pretty much hosed.
goto would also be a solution but for this particular sample I'd not go with it.
A lighter way is to put at least the fail call into a function or lambda, what still leaves you with the continue part.
I'd probably make a macro that takes the filter expression as argument, leaving code like.
if(type == "bool")
{
ENSURE(values->Has(1) && values->Get(1)->IsBoolean());
stg->Set<bool>(key, values->Get(1)->BooleanValue());
}
...
it's ok to pass a tuple as argument of a method, but as soon as I want to pass the tuple to a method of a class it doesn't work(I get a Run Failed at the row "ret = PyEval_CallObject(method,args);"
thanks a lot if someone knows why it doesn't work
the following code used is:
enter code Python Code:
class cVector:
def __init__(self,msg):
self.value = msg
def ComputeNorm(self,vecData):
#don't use vecData for instance
result = 12.
return(result)
enter C++ Code
PyObject *ret, *mymod, *pclass, *method, *args, *object;
float retValue;
Py_Initialize();
PySys_SetPath(".");
// Module
mymod = PyImport_ImportModule("mModule8");
if (mymod == NULL){
cout << "Can't Open a module:\n" ;
Py_DECREF(mymod);
}
// Class
pclass = PyObject_GetAttrString(mymod, "cVector");
if (pclass == NULL) {
Py_DECREF(pclass);
cout << "Can't find class\n";
}
// Parameters/Values
args = Py_BuildValue("(f)", 100.0);
if (args == NULL) {
Py_DECREF(args);
cout << "Can't build argument list for class instance\n";
}
// Object with parameter/value
object = PyEval_CallObject(pclass, args);
if (object == NULL) {
Py_DECREF(object);
cout << "Can't create object instance:\n";
}
// Decrement the argument counter as we'll be using this again
Py_DECREF(args);
// Get the object method - note we use the object as the object
// from which we access the attribute by name, not the class
method = PyObject_GetAttrString(object, "ComputeNorm");
if (method == NULL) {
Py_DECREF(method);
cout << "Can't find method\n";
}
// Decrement the counter for our object, since we now just need
// the method reference
Py_DECREF(object);
// Build our argument list - an empty tuple because there aren't
// any arguments
cout << "Prepare the Tuple:\n" ;
// WE pass a tuple
args = PyTuple_New( 3 );
if (args == NULL) {
Py_DECREF(args);
cout << "Can't build argument list for method call\n";
}
PyObject *py_argument;
// 1st argument
py_argument = PyFloat_FromDouble(5.);
PyTuple_SetItem(args, 0, py_argument);
// 2nd argument
py_argument = PyFloat_FromDouble(10.);
PyTuple_SetItem(args, 1, py_argument);
// 3nd argument
py_argument = PyFloat_FromDouble(15.);
PyTuple_SetItem(args, 2, py_argument);
cout << "Before the Exec:\n" ;
// Call our object method with arguments
ret = PyEval_CallObject(method,args);
//ret = PyObject_CallObject(method,args);
if (ret == NULL) {
Py_DECREF(ret);
cout << "Couldn't call method\n";
}
// Convert the return value back into a C variable and display it
PyArg_Parse(ret, "f", &retValue);
printf("RetValue: %f\n", retValue);
// Kill the remaining objects we don't need
Py_DECREF(method);
Py_DECREF(ret);
// Close off the interpreter and terminate
Py_Finalize();
You don't show how you obtain method. You have to get it from an instance for this to work (here I assume that inst is a PyObject* pointing to an instance of cVector class):
PyObject *method = PyObject_GetAttrString(inst, "ComputeNorm");
Always check for errors:
if (method == NULL)
return NULL;
(or do other appropriate thing, depending on the context)
Then, your code can be greatly shortened:
PyObject *args = Py_BuildValue("(ddd)", 5.0, 10.0, 15.0);
(this creates a tuple with three Python floats made from C doubles)
or even combined with the call:
PyObject *ret = PyObject_CallFunction(method, "(ddd)", 5.0, 10.0, 15.0);
You call even combine everything in one call:
PyObject *ret = PyObject_CallMethod(inst, "ComputeNorm",
"(ddd)", 5.0, 10.0, 15.0);
Again, remeber to check for errors:
if (ret == NULL)
return NULL;
And always decref all the objects you create and don't need anymore (otherwise you will be leaking memory):
Py_DECREF(ret);
(assuming you've used the PyObject_CallMethod, otherwise you might have to decref args and method as well)