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 я должен неправильно настроить массив указателей или что-то в этом роде. Кажется, что он попадает на второй узел в цикле, а затем возникает проблема, как я видел, выплевывая данные в командную строку. Любое понимание будет высоко ценится.

8

Решение

Следующий код работает:

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
10

Другие решения

В этой строке:

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);
4

Я не могу (легко) протестировать код, но исходя из того, что вы сказали, я думаю, что проблема заключается в строке …

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) вместо.

2
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector