2

From the official docs ;

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
    fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
    exit(1);
}
Py_SetProgramName(program);  /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
                   "print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
    exit(120);
}
PyMem_RawFree(program);
return 0;
}

I successfully ran this piece. I am trying to get output of PyRun_SimpleString to a string variable, let's say

char string[50];

I went through the documentation but couldn't come up with a result. As far as I can tell there are multiple ways to achieve this tiny task and is in the orders of a couple of additional lines. I would appreciate a guidence or a workaround regarding this manner.

3
  • You seem to have taken the sample code in your question from Python docs. The next example on the same page explains this in detail. What specific information do you need? Commented Jul 29, 2020 at 23:40
  • As I stated at the beginning of original post, code is from official document pages already. Example at the next page points to a structure that calls a function from a script file with arguments and the rest. What I am trying to do is just to simply assign output of PyRun_SimpleString() to a char array so to speak to a string variable. Commented Jul 29, 2020 at 23:46
  • Why are you printing the output? You wouldn't use printf for this in C. Why would you use print in Python? Commented Jul 30, 2020 at 1:16

1 Answer 1

0

I wish I had found a better way, but this way seems to work, (will update if I find a better solution):

If you defined a class in Python to catch sys.stdout writes:

import sys
class CatchOutErr:
    def __init__(self):
        self.value = ''
    def write(self, txt):
        self.value += txt
catchOutErr = CatchOutErr()
sys.stdout = catchOutErr
sys.stderr = catchOutErr

And you passed the value received from this handler to C++, converted to string, etc...

#include <Python.h>
#include <iostream>
#include <stdio.h>

int main(int argc, char *argv[])
{

    Py_Initialize();
    PyObject *pModule = PyImport_AddModule("__main__"); //create main module
    std::string stdOutErr = "import sys\nclass CatchOutErr:\n\tdef __init__(self):\n\t\tself.value = ''\n\tdef write(self, txt):\n\t\tself.value += txt\ncatchOutErr = CatchOutErr()\nsys.stdout = catchOutErr\nsys.stderr = catchOutErr\n";

    PyRun_SimpleString(stdOutErr.c_str()); //invoke code to redirect
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    PyObject *catcher = PyObject_GetAttrString(pModule, "catchOutErr"); //get our catchOutErr created above
    PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object
    std::string s = PyString_AsString(output);
    Py_DECREF(catcher);
    Py_DECREF(output);
    Py_DECREF(s);
    std::cout << s;
    return 0;
}

('Today is', 'Thu Jul 30 09:02:55 2020')

For Python3:

...
PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object
PyObject *encodedData = PyUnicode_AsEncodedString(output, "ascii", NULL);
Py_DECREF(output);
Py_DECREF(encodedData);
char* buf;
Py_ssize_t len;
PyBytes_AsStringAndSize(encodedData, &buf, &len);
std::cout << std::string(buf) << std::endl;

Reference: https://stackoverflow.com/a/4307737/9238288 https://cpp.hotexamples.com/examples/-/-/PyUnicode_AsEncodedString/cpp-pyunicode_asencodedstring-function-examples.html

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the answer. Your approach seems to work from my end as well.

Your Answer

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