gpt4 book ai didi

Python CFFI - 无法在函数调用中使用格式化的 Python 字符串作为字节数组

转载 作者:行者123 更新时间:2023-11-30 15:07:25 25 4
gpt4 key购买 nike

我正在学习如何将用 C 编写的代码包含到 Python 中,因为我有一个用于 Microchip 设备的 API,这对于我希望通过为其添加一个 Python 包装器来让我将来的生活更轻松,这将使我能够更快地测试东西。一种方法是使用 cffi 模块,该模块甚至为用户提供了 verify() ,该模块基本上调用 C 编译器来检查是否提供的 cdef(...) 是正确的。

我编写了一个小项目,以便我可以首先学习如何正确使用cffi。它由两部分组成

  1. Library - 用 C 编写。我相应地使用 cmakemake 来编译其代码:

    CMakeLists.txt

    project(testlib_for_cffi)
    cmake_minimum_required(VERSION 2.8)

    set(CMAKE_BUILD_TYPE Release)
    set(CMAKE_CXX_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
    # Debug build
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -g -O0")
    # Release build
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os")

    aux_source_directory(. SRC_LIST)
    add_library(testcffi SHARED ${SRC_LIST})

    # Not required for the library but needed if I want to check for memory leaks with Valgrind
    set(SRC main.c)
    add_executable(${PROJECT_NAME} ${SRC})
    target_link_libraries(${PROJECT_NAME} PUBLIC testcffi)

    testcffi.h

    typedef struct
    {
    double x;
    double y;
    double z;
    char *label;
    } point_t;

    // Creation, printing and deletion
    point_t* createPoint(double x, double y, double z, char *label);
    void printPoint(point_t *point);
    void deletePoint(point_t *point);

    testcffi.c

    #include "testcffi.h"
    #include <stdio.h>
    #include <malloc.h>

    point_t* createPoint(double x, double y, double z, char *label) {
    point_t *p = malloc(sizeof(point_t));
    p->x = x;
    p->y = y;
    p->z = z;
    p->label = label;

    return p;
    }

    void printPoint(point_t *point) {
    if(point == NULL) return;
    printf("Data:\n\tx : %f\n\ty : %f\n\tz : %f\n\tmsg : \"%s\"\n", point->x, point->y, point->z, point->label);
    }

    void deletePoint(point_t *point) {
    if(point == NULL) return;
    free(point);
    point = NULL;
    }
  2. Python 中的测试代码 - 该代码演示了 struct 以及上述库中的三个函数的用法:

            #!/usr/bin/python3

    from cffi import FFI
    import random

    ffi = FFI()

    # Add library's header
    ffi.cdef('''
    typedef struct
    {
    double x;
    double y;
    double z;
    char * label;
    } point_t;

    // Creation, printing and deletion
    point_t * createPoint(double x=0., double y=0., double z=0., char *label="my_label");
    void printPoint(point_t *point);
    void deletePoint(point_t *point);
    ''')

    # Load shared object from subdirectory `build`
    CLibTC = ffi.dlopen('build/libtestcffi.so')

    def createList(length=5):
    if len:
    lst = []
    for i in range(0, length):
    lst.append(CLibTC.createPoint(
    float(random.random()*(i+1)*10),
    float(random.random()*(i+1)*10),
    float(random.random()*(i+1)*10),
    b'hello' # FIXME Why does ONLY this work?
    # ('point_%d' % i).encode('utf-8') # NOT WORKING
    # 'point_{0}'.format(str(i)).encode('utf-8') # NOT WORKING
    # ffi.new('char[]', 'point_{0}'.format(str(i)).encode('utf-8')) # NOT WORKING
    ))

    return lst
    return None


    def printList(lst):
    if lst and len(lst):
    for l in lst:
    CLibTC.printPoint(l)

    list_of_dstruct_ptr = createList(10)
    printList(list_of_dstruct_ptr)

问题来自于我必须将 Python 字符串转换为的字节数组,以便将数据传递到我的 C 代码中的相应位置。

上面的代码可以工作,但是我想使用类似于 b'hello' 的其他字符串。这就是为什么我尝试在 Python 中使用 format() (及其简写形式 %)来组合一堆字母和一个数字但是。但没有成功。我要么将 "" 作为我的 point_t structlabel 参数的值,要么得到一个奇怪的交替垃圾数据(主要是既不是字母也不是数字的奇怪字符)。

我认为我错误地使用了 encode() 函数,但是当我在 Python 交互式 shell 中测试它时,我得到了与使用 相同的输出b'...'.

知道这是怎么回事吗?

<小时/>

一个很高兴知道的问题:从我到目前为止所读到的内容来看,cffi似乎使用了Python中的垃圾收集> 释放 C 代码中动态分配的内存。我已经用很多点对其进行了测试,但我想确保实际上总是如此。

<小时/>

更新:好吧,看起来没有 new(...) 的东西确实可以工作,但是在这种情况下,所有值都与循环中的最后一个值相同。例如,如果循环达到 10,则所有 struct Python 对象的标签中都将包含 10。这似乎是一个引用问题。当我使用 new(...) 时,我得到垃圾数据。

最佳答案

在您的 C 代码中,point_t 结构在 label 中保存一个 char *,即指向内存中其他位置的指针。如果您创建 10 个 point_t 结构,它们将保存指向内存中其他位置的 10 个字符串的指针。只要您使用 point_t 结构,您就必须确保这 10 个字符串保持事件状态。 CFFI无法猜测有这样的关系。当您执行调用 CLibTC.createPoint(..., some_string) 时,CFFI 会在调用周围分配一个 char[] 数组并复制 some_string在其中,但是这个 char[] 内存在调用后被释放。

改用这种代码:

c_string = ffi.new("char[]", some_string)
lst.append(createPoint(..., c_string))
keepalive.append(c_string)

其中 keepalive 是另一个列表,只要您需要 point_t 包含有效的标签,您就必须确保该列表保持事件状态' s。

关于Python CFFI - 无法在函数调用中使用格式化的 Python 字符串作为字节数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38282126/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com