简体   繁体   English

如何使用cffi嵌入在C语言中返回字符串的Python函数?

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

I'm trying to embed a Python function in C using PyPy and cffi. 我正在尝试使用PyPy和cffi将Python函数嵌入C中。 I'm following this guide from the PyPy documentation. 我正在遵循PyPy文档中的本指南

The problem is, all the examples I've found operate on ints, and my function takes a string and returns a string. 问题是,我发现的所有示例都在ints上操作,并且我的函数采用字符串并返回字符串。 I can't seem to figure out how to embed this function in C, as C doesn't seem to really have strings, rather making do with arrays of chars. 我似乎无法弄清楚如何将此函数嵌入C中,因为C似乎并没有真正的字符串,而是使用char数组。

Here's what I've tried: 这是我尝试过的:

# interface.py

import cffi

ffi = cffi.FFI()
ffi.cdef('''
struct API {
    char (*generate_cool_page)(char url[]);
};
''')

...


@ffi.callback("char[] (char[])")
def generate_cool_page(url):
    # do some processing with BS4
    return str(soup)

def fill_api(ptr):
    global api 
    api = ffi.cast("struct API*", ptr)
    api.generate_cool_page = generate_cool_page

-- -

// c_tests.c

#include "PyPy.h"
#include <stdio.h>
#include <stdlib.h>

struct API {
    char (*generate_cool_page)(char url[]);
};

struct API api;   /* global var */

int initialize_api(void)
{
    static char source[] =
        "import sys; sys.path.insert(0, '.'); "
        "import interface; interface.fill_api(c_argument)";
    int res;

    rpython_startup_code();
    res = pypy_setup_home(NULL, 1);
    if (res) {
        fprintf(stderr, "Error setting pypy home!\n");
        return -1;
    }
    res = pypy_execute_source_ptr(source, &api);
    if (res) {
        fprintf(stderr, "Error calling pypy_execute_source_ptr!\n");
        return -1;
    }
    return 0;
}

int main(void)
{
    if (initialize_api() < 0)
        return 1;

    printf(api.generate_cool_page("https://example.com"));

    return 0;
}

When I run gcc -I/opt/pypy3/include -Wno-write-strings c_tests.c -L/opt/pypy3/bin -lpypy3-c -g -o c_tests and then run ./c_tests , I get this error: 当我运行gcc -I/opt/pypy3/include -Wno-write-strings c_tests.c -L/opt/pypy3/bin -lpypy3-c -g -o c_tests然后运行./c_tests ,出现此错误:

debug: OperationError:
debug:  operror-type: CDefError
debug:  operror-value: cannot render the type <char()(char *)>: it is a function type, not a pointer-to-function type
Error calling pypy_execute_source_ptr!

I don't have a ton of experience with C and I feel like I'm misrepresenting the string argument/return value. 我没有使用C的大量经验,感觉好像我在错误地表示字符串参数/返回值。 How do I do this properly? 如何正确执行此操作?

Thanks for your help! 谢谢你的帮助!

Note that you should not be using pypy's deprecated interface to embedding; 请注意,您不应使用pypy弃用的界面进行嵌入; instead, see http://cffi.readthedocs.io/en/latest/embedding.html . 相反,请参见http://cffi.readthedocs.io/en/latest/embedding.html

The C language doesn't have "strings", but only arrays of chars. C语言没有“字符串”,而只有字符数组。 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; 在C语言中,要返回“字符串”的函数通常用不同的方式写成:它接受指向预先存在的缓冲区(类型为char[] )的指针作为第一个参数,并将该缓冲区的长度作为第二个参数; and when called, it fills the buffer. 并在调用时填充缓冲区。 This can be messy because you ideally need to handle buffer-too-small situations in the caller, eg allocate a bigger array and call the function again. 这可能很麻烦,因为理想情况下,您需要在调用程序中处理缓冲区太小的情况,例如分配更大的数组并再次调用该函数。

Alternatively, some functions give up and return a freshly malloc() -ed char * . 或者,某些函数放弃并返回一个新的malloc() ed char * Then the caller must remember to free() it, otherwise a leak occurs. 然后,调用者必须记住将其free() ,否则会发生泄漏。 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:: 假设您从http://cffi.readthedocs.io/en/latest/embedding.html开始,请将plugin.h更改为包含:

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

And change this bit of plugin_build.py :: 并更改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; 在C代码中,在新的嵌入模式下根本不需要initialize_api() instead, you just say #include "plugin.h" and call the function directly:: 而是说#include "plugin.h"并直接调用该函数:

char *data = generate_cool_page("https://example.com");
if (data == NULL) { handle_errors... }
printf("Got this: '%s'\n", data);
free(data);   // important!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 cffi:如何将字符串字符的地址发送给C函数? - cffi: How do i send the address of a character of a string to a C function? 如何使用Python的CFFI将指针传递给C函数? - How do I pass a pointer to a C function with Python's CFFI? 如何在Python中获取CFFI函数的`const`修饰符? - How can I get the `const` modifier of a CFFI function in Python? 我们如何在 Java(JNA) 中获取由 Python function 使用 CFFI 返回的字符串 - How do we get String in Java(JNA), that returned by Python function using CFFI 使用 CFFI 从 Python 调用带有 OpenMP 的 C 函数 - Using CFFI to call C-function with OpenMP from Python 使用CFFI从Python传递指向C函数的指针的最佳方法 - Best way to pass pointer to C function from Python using CFFI 如何使用 CFFI 将包含其标头的 C 库包装到 python 程序中? - How do I wrap a C-library including its header into a python program using CFFI? 使用 CFFI 在 Fortran 中使用 Python 函数。 cffi 构建中的警告。 我无法通过控制台或文件中的打印获得结果,但在运行时不会出错 - Use CFFI for using Python function inside Fortran. Warnings in cffi build. I can't get results from print in console or file, but not error in running 如何使用 CFFI 将多维 Numpy 数组传递给 C 函数? - How to pass multidimensional Numpy arrays to C function using CFFI? 如何在Python中实现一个C接口并使用CFFI传递对象 - How to implement a C interface in Python and pass objects using CFFI
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM