How can I embed a Python function that returns a string in C using cffi?

拜拜、爱过 提交于 2019-12-06 07:02:13

Note that you should not be using pypy's deprecated interface to embedding; instead, see http://cffi.readthedocs.io/en/latest/embedding.html.

The C language doesn't have "strings", but only arrays of chars. In C, a function that wants to return a "string" is usually written differently: it accepts as first argument a pointer to a pre-existing buffer (of type char[]), and as a second argument the length of that buffer; and when called, it fills the buffer. This can be messy because you ideally need to handle buffer-too-small situations in the caller, e.g. allocate a bigger array and call the function again.

Alternatively, some functions give up and return a freshly malloc()-ed char *. Then the caller must remember to free() it, otherwise a leak occurs. I would recommend that approach in this case because guessing the maximum length of the string before the call might be difficult.

So, something like that. Assuming you start with http://cffi.readthedocs.io/en/latest/embedding.html, change plugin.h to contain::

// return type is "char *"
extern char *generate_cool_page(char url[]);

And change this bit of plugin_build.py::

ffibuilder.embedding_init_code("""
    from my_plugin import ffi, lib

    @ffi.def_extern()
    def generate_cool_page(url):
        url = ffi.string(url)
        # do some processing
        return lib.strdup(str(soup))   # calls malloc()
""")
ffibuilder.cdef("""
    #include <string.h>
    char *strdup(const char *);
""")

From the C code, you don't need initialize_api() at all in the new embedding mode; instead, you just say #include "plugin.h" and call the function directly::

char *data = generate_cool_page("https://example.com");
if (data == NULL) { handle_errors... }
printf("Got this: '%s'\n", data);
free(data);   // important!
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!