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

2023-12-05

我正在尝试使用 PyPy 和 cffi 在 C 中嵌入 Python 函数。我正在跟进本指南来自 PyPy 文档。

问题是,我发现的所有示例都对整数进行操作,而我的函数接受一个字符串并返回一个字符串。我似乎不知道如何在 C 中嵌入这个函数,因为 C 似乎没有真正的字符串,而是使用字符数组。

这是我尝试过的:

# 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!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 cffi 在 C 中嵌入返回字符串的 Python 函数? 的相关文章

随机推荐

  • 有没有办法回答(或忽略)所有 y/n 提示的“y”?

    我有一个 Jupyter 笔记本 里面有很多大变量 有一次我想扔掉所有我已经用完的变量 我使用 reset selective 变量名来清除每个变量 但这些变量有 60 个 当我运行包含所有 60 个提示的块时 它会要求我为每个清除输入 y
  • 使用c#在Word中按名称访问表

    我有一个包含很多表格的文档 我想使用 C 和 Microsoft Office Interop Word 修改这些表 我读到我可以使用 Tables 接口迭代所有表 问题 是否可以为表指定名称 ID 并通过名称访问表 就像 Powerpoi
  • 通过 github API 关闭拉取请求

    根据我们应用程序的设计要求 我们曾经使用 gitlab API 删除 Gitlab 中的合并请求 现在我们正在迁移到 Github 我正在寻找类似的 API 调用来关闭 Github 上的拉取请求 我通读了文档here 但它没有回答我的问题
  • 对数据框的每一行进行排序[重复]

    这个问题在这里已经有答案了 我正在尝试使用这一行对数据框的每一行进行排序 sapply df function x sort x 但是 对列进行排序而不是对行进行排序 例如 这个数据框 5 10 7 1 5 6 3 9 2 4 4 5 1
  • *a, b, c = line.split() 中的星号有什么作用?

    Assume line is Chicago Sun 01 52 什么是 a b c line split 做 特别是 星号的意义是什么 编辑 经过测试 似乎 Chicago Sun and 01 52 都存储在a b and c 星号似乎
  • 一级缓存可以与 ICriteria 或其他 API 一起使用吗?

    In NHibernate使用时您可以轻松地从一级缓存中受益Load or Get方法 但是关于ICriteria HQL Linq to NHibernate and QueryOver 他们也使用一级缓存吗 他们使用它来返回实体 但查询
  • PowerMockito.doReturn 返回 null

    这是我正在测试的课程 public class A public Integer callMethod return someMethod private Integer someMethod Some Code HttpPost http
  • 在Linux上,如何确保解锁被锁定在死亡/终止的线程中的互斥体?

    这是一道面试题 在 Linux 上 如何确保解锁被锁定在死亡 终止的 POSIX 线程中的 POSIX 互斥锁 我的想法 Linux向程序发送kill或终止信号时会自动释放它吗 但是 我找不到有关操作系统如何执行此操作的更多详细信息 tha
  • Facebook.php 和 facebookapi_php5 文档

    我在哪里可以找到关于这两个 PHP 文件的良好文档以及每个函数的更详细和深入的使用 Facebook 文档 信息不够丰富 哈哈 我感受到你的痛苦 facebookapi php5主要是各个API方法 facebook 主要用于会话 身份验证
  • 如何动态添加新方法到 php 对象?

    如何 即时 向对象添加新方法 me new stdClass me gt doSomething function echo I ve done something me gt doSomething Fatal error Call to
  • Cordova 文件插件在 Android 中从未准备就绪

    我有一个非常简单的 Cordova 应用程序 只有一个插件 org apache cordova file 当我在 Android 模拟器中模拟该应用程序时 deviceready事件永远不会被触发 我得到以下输出 D CordovaLog
  • Zend Framework 2 - 注释表单不起作用

    谢谢 光新藤我调查了AnnotationForms这似乎是最好的解决方法ModelForms 但示例所示here对我不起作用 use Zend Form Annotation AnnotationBuilder builder new An
  • 构建项目时出现转换异常[重复]

    这个问题在这里已经有答案了 当我尝试运行我的应用程序时 出现以下错误 Error Execution failed for task app transformClassesWithDexForDebug gt com android bu
  • 绑定和解构块参数

    在 ruby 中 有没有一种方法可以同时将块的参数绑定到局部变量并对其进行解构 谷歌搜索没有找到我任何东西 并且在 IRB 中玩也毫无结果 但我想我回想起了类似于以下功能的功能 gt gt 1 2 3 4 map x y z x y z g
  • 将 DateTime.Add(TimeSpan) 与 LINQ 结合使用

    我必须运行如下查询 它实际上更复杂 但这里是重要的部分 var results from b in context Bookings where b ScheduleDate Add b StartTime gt DateTime UtcN
  • 批次中的随机生成器

    我有一个bat文件 echo RANDOM 并使用命令行执行它 start randomcheck bat start randomcheck bat 打开两个控制台 并且都包含相同的数字 4645 这无法达到随机的目的提供不同的临时文件夹
  • ASP.Net Core 文件上传进度会话

    我正在 ASP Net Core 中编写文件上传 并尝试更新进度栏 但是当从 javascript 调用 进度 操作时 会话值未正确更新 进度使用以下方式保存在用户会话中 public static void StoreInt ISessi
  • 如何在 Windows 上使用 python 2.6 安装 pip

    我尝试在我的开发计算机上安装带有 python 2 6 的 pip 以尝试匹配也使用 python 2 6 的部署环境 Python 2 6 安装正常 我尝试使用 get pip py 安装 pip 如此处所述https pip pypa
  • 使用 .NET Core System.Text.Json 序列化/反序列化类层次结构

    我有一个简单的类层次结构 我想使用 System Text Json 对其进行序列化 有3个班级 基地是Shape 继承的有Box and Circle 我计划在我的前端应用程序上使用这些类作为标记联合 所以我刚刚引入了一个鉴别器属性Tag
  • 如何使用 cffi 在 C 中嵌入返回字符串的 Python 函数?

    我正在尝试使用 PyPy 和 cffi 在 C 中嵌入 Python 函数 我正在跟进本指南来自 PyPy 文档 问题是 我发现的所有示例都对整数进行操作 而我的函数接受一个字符串并返回一个字符串 我似乎不知道如何在 C 中嵌入这个函数 因