2

I used the code in this answer to create the following file

callpython.c

#include </usr/include/python2.7/Python.h>

int
main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc;
    PyObject *pArgs, *pValue;
    int i;

    if (argc < 3) {
        fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
        return 1;
    }

    Py_Initialize();
    pName = PyString_FromString(argv[1]);
    /* Error checking of pName left out */
    //fprintf(stderr,"pName is %s\n", pName);
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\".\")");
    //PySys_SetArgv(argc, argv);

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, argv[2]);
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(argc - 3);
            for (i = 0; i < argc - 3; ++i) {
                pValue = PyInt_FromLong(atoi(argv[i + 3]));
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                } 
                /* iValue reference stolen here: */
                PyTuple_SetItem(pArgs, i, pValue);
                //PyTuple_SetItem(pArgs, i, argv[i + 3]);
            }
            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
    Py_Finalize();
    return 0;
}

I created another file in the same directory as helloWorld.py. The contents of this python script are

def helloworldFunc(a):
    print 'Hello '+str(a)

I compile and run callpython.c as below

 g++ -o callpython callpython.c -lpython2.7 -lm -L/usr/lib/python2.7/config && ./callpython helloworld helloworldFunc world

Rather than printing "Hello world", it prints "Hello 0"

Why does it not parse the python function argument as string?

2
  • Have you tried to use a debugger? Have you tried to run the program with more arguments? Commented May 21, 2018 at 3:33
  • @n.m. pls see my answer. Commented May 21, 2018 at 3:42

2 Answers 2

2

The sample code is parsing the arguments as integers, buy you've passed a string. atoi("world") returns 0, so that's the integer you get:

/* Create tuple of the correct length for the arguments. */
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
   /* Convert each C argv to a C integer, then to a Python integer. */
    pValue = PyInt_FromLong(atoi(argv[i + 3]));
    if (!pValue) {
        Py_DECREF(pArgs);
        Py_DECREF(pModule);
        fprintf(stderr, "Cannot convert argument\n");
        return 1;
    } 
    /* iValue reference stolen here: */
    /* Store the Python integer in the tuple at the correct offset (i) */
    PyTuple_SetItem(pArgs, i, pValue);
}

Change the conversion line to the following to handle any string:

pValue = PyString_FromString(argv[i + 3]);
Sign up to request clarification or add additional context in comments.

Comments

0

Solved the issue. The culprit was this line

pValue = PyInt_FromLong(atoi(argv[i + 3]));

It was parsing each argument to python script as an integer.

When replaced with the following line, it parses each argument as a string

pValue = PyString_FromString(argv[i+3]);

I haven't really understood how pValue works, but this solves the problem for now.

4 Comments

Ha, you answered while I was prepping mine.
@MarkTolonen Thanks, if, in your answer, you could add an explanation of PyTuple_SetItem(pArgs, i, pValue); that would be great!
PyTuple_New() creates a tuple equal in size to the number of arguments to the function. PyTuple_SetItem() sets the corresponding element of the tuple to the pValue object generated for each argument. See PyTuple_SetItem in the documentation for more details.
Updated my answer as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.