Python使用ctypes传递char*数组并填充结果

2024-05-16 19:17:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图使用ctypes在python中创建一个char*数组,传递给一个库来填充字符串。我希望4个字符串的长度不超过7个字符。

我的py代码是这样的

测试库.py

from ctypes import *
primesmile = CDLL("/primesmile/lib.so")

getAllNodeNames = primesmile.getAllNodeNames
getAllNodeNames.argtypes = [POINTER(c_char_p)]
results = (c_char_p * 4)(addressof(create_string_buffer(7)))
err = getAllNodeNames(results)

库cpp

void getAllNodeNames(char **array){
    DSL_idArray nodes; //this object returns const char * when iterated over
    network.GetAllNodeIds(nodes);
    for(int i = 0; i < (nodes.NumItems()); i++){
    strcpy(array[i],nodes[i]);
    }
}

当我试图运行这个代码时,我不断地遇到分段错误。我已经用C创建了一个测试,它工作得很好,但是在Python中,我必须错误地设置指针数组或其他东西。它似乎到达了循环中的第二个节点,然后出现了一个问题,正如我在将数据吐出到命令行中看到的那样。任何洞察都将不胜感激。


Tags: 字符串代码frompy错误数组ctypesarray
3条回答

在这一行中:

results = (c_char_p * 4)(addressof(create_string_buffer(7)))

创建一个7字节的缓冲区,然后尝试使用它保存4个字符指针(每个指针可能4个字节),然后将4个8字节的字符串复制到它可能指向的随机地址中。您需要为每个字符串分配一个缓冲区,还需要分配指针数组。像这样的:

s = []
for i in range(4):
    s[i] = create_string_buffer(8)
results = (c_char_p * 4)(s);

以下代码有效:

测试.py:

import ctypes
lib = ctypes.CDLL("./libtest.so")
string_buffers = [ctypes.create_string_buffer(8) for i in range(4)]
pointers = (ctypes.c_char_p*4)(*map(ctypes.addressof, string_buffers))
lib.test(pointers)
results = [s.value for s in string_buffers]
print results

test.c(使用gcc test.c -o libtest.so -shared -fPIC编译为libtest.so):

#include <string.h>
void test(char **strings) {
    strcpy(strings[0],"this");
    strcpy(strings[1],"is");
    strcpy(strings[2],"a");
    strcpy(strings[3],"test!");
}

正如阿雅所说,你应该确保有足够的空间来终止零点。但我认为您的主要问题是字符串缓冲区被垃圾收集或类似的东西,因为不再有直接引用它。或者在没有为字符串缓冲区存储引用的情况下,其他原因导致了创建过程中的问题。例如,这将导致四倍于相同地址而不是不同地址:

import ctypes
pointers = [ctypes.addressof(ctypes.create_string_buffer(8)) for i in range(4)]
print pointers

我不能(很容易)测试代码,但根据你所说的,我猜问题出在这一行。。。

results = (c_char_p * 4)(addressof(create_string_buffer(7)))

根据Python文档中的^{}。。。

init_or_size must be an integer which specifies the size of the array, or a string which will be used to initialize the array items.

If a string is specified as first argument, the buffer is made one item larger than the length of the string so that the last element in the array is a NUL termination character. An integer can be passed as second argument which allows to specify the size of the array if the length of the string should not be used.

…这意味着它正在创建一个char[7],但是strcpy()将尝试复制字符串的NULL终止符,因此,如果最大“节点名”长度为7个字符,则需要一个char[8]来保存NULL,尽管您可能可以使用memcpy(array[i], nodes[i], 7)而不是strcpy()

不管怎样,用create_string_buffer(8)代替可能是最安全的。

相关问题 更多 >