Python, использующий ctypes для передачи массива char * и заполнения результатов
Я пытаюсь использовать ctypes для создания массива char * в python для передачи в библиотеку для заполнения строками. Я ожидаю, что 4 строки возвращают не более 7 символов в длину.
Мой код Py выглядит так
testlib.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)
lib.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 я должен неправильно настроить массив указателей или что-то в этом роде. Кажется, что он попадает на второй узел в цикле, а затем возникает проблема, как я видел, выплевывая данные в командную строку. Любое понимание будет высоко ценится.
3 ответа
Следующий код работает:
test.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 (скомпилирован в libtest.so с gcc test.c -o libtest.so -shared -fPIC
):
#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)))
Вы создаете один буфер из 7 байтов, затем пытаетесь использовать его для хранения 4-х символьных указателей (вероятно, каждый по 4 байта), а затем копируете 4 8-байтовые строки в случайные адреса, на которые может указывать. Вам необходимо выделить буфер для каждой строки, а также выделить массив указателей. Что-то вроде этого:
s = []
for i in range(4):
s[i] = create_string_buffer(8)
results = (c_char_p * 4)(s);
Я не могу (легко) протестировать код, но исходя из того, что вы сказали, я думаю, что проблема заключается в строке...
results = (c_char_p * 4)(addressof(create_string_buffer(7)))
В соответствии с документами Python для create_string_buffer()
...
init_or_size
должно быть целым числом, определяющим размер массива, или строкой, которая будет использоваться для инициализации элементов массива.Если строка указана в качестве первого аргумента, буфер делается на один элемент больше, чем длина строки, так что последний элемент в массиве является символом завершения NUL. Целое число может быть передано в качестве второго аргумента, который позволяет указать размер массива, если длина строки не должна использоваться.
... что подразумевает создание char[7]
, но strcpy()
будет пытаться скопировать NULL
терминатор для строки, поэтому, если ваша максимальная длина "имя узла" составляет семь символов, вам понадобится char[8]
держать NULL
, хотя вы могли бы избежать использования memcpy(array[i], nodes[i], 7)
вместо strcpy()
,
В любом случае, это, вероятно, самый безопасный для использования create_string_buffer(8)
вместо.