簡體   English   中英

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

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

我正在嘗試使用PyPy和cffi將Python函數嵌入C中。 我正在遵循PyPy文檔中的本指南

問題是,我發現的所有示例都在ints上操作,並且我的函數采用字符串並返回字符串。 我似乎無法弄清楚如何將此函數嵌入C中,因為C似乎並沒有真正的字符串,而是使用char數組。

這是我嘗試過的:

# 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;
}

當我運行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!

我沒有使用C的大量經驗,感覺好像我在錯誤地表示字符串參數/返回值。 如何正確執行此操作?

謝謝你的幫助!

請注意,您不應使用pypy棄用的界面進行嵌入; 相反,請參見http://cffi.readthedocs.io/en/latest/embedding.html

C語言沒有“字符串”,而只有字符數組。 在C語言中,要返回“字符串”的函數通常用不同的方式寫成:它接受指向預先存在的緩沖區(類型為char[] )的指針作為第一個參數,並將該緩沖區的長度作為第二個參數; 並在調用時填充緩沖區。 這可能很麻煩,因為理想情況下,您需要在調用程序中處理緩沖區太小的情況,例如分配更大的數組並再次調用該函數。

或者,某些函數放棄並返回一個新的malloc() ed char * 然后,調用者必須記住將其free() ,否則會發生泄漏。 在這種情況下,我建議使用這種方法,因為在調用之前猜測字符串的最大長度可能很困難。

所以,類似的東西。 假設您從http://cffi.readthedocs.io/en/latest/embedding.html開始,請將plugin.h更改為包含:

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

並更改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 *);
""")

在C代碼中,在新的嵌入模式下根本不需要initialize_api() 而是說#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM