2013-05-22 12 views
8

Próbuję użyć ctypes, aby utworzyć tablicę char * w pythonie, która zostanie przekazana do biblioteki i wypełniona ciągami. Spodziewam się, że 4 ciągi z powrotem nie będą dłuższe niż 7 znaków.Python za pomocą ctypes przekazuje tablicę char * i zapełnia wyniki

Mój kod py wygląda to

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]); 
    } 
} 

Wciąż dostaję naruszenie ochrony pamięci, gdy próbuję uruchomić ten kod . Stworzyłem test z C, który działa doskonale, ale w Pythonie muszę ustawiać tablicę wskaźnika niepoprawnie lub coś podobnego. Wydaje się, że dostaje się do drugiego węzła w pętli, a następnie ma problem, jak widziałem od wypluwania danych do wiersza poleceń. Każdy wgląd byłby bardzo doceniany.

Odpowiedz

9

Poniższy kod działa:

testu.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 (skompilowany do libtest.so z 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!"); 
} 

Jak powiedział Aya, należy upewnić się, że nie ma miejsca na kończące zera. Ale myślę, że twoim głównym problemem było to, że bufor łańcuchowy był zbiorem śmieci lub czymś podobnym, ponieważ nie było już bezpośredniego odniesienia do niego. Lub coś innego powoduje problemy w procesie tworzenia buforów ciągów, gdy nie są dla nich przechowywane odniesienia. Na przykład skutkuje czterokrotnie samego adresu zamiast różnych adresów:

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

można również tworzyć tablicy 2D dla buforu: 'string_buffers = ((ctypes.c_char * 8) * 4)()'. Powtórzę to samo, gdy zdefiniujesz "wskaźniki" w następnym wierszu. – eryksun

2

nie mogę (łatwo) przetestować kod, ale na podstawie tego, co pan powiedział, moje przypuszczenie byłby problem leży w linii ...

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

Zgodnie z docs Pythona create_string_buffer() ...

init_or_size musi być liczbą całkowitą, która określa rozmiar tablicy, lub ciąg, który będzie używany do zainicjowania elementów tablicy.

Jeśli jako pierwszy argument zostanie podany łańcuch, bufor zostanie utworzony o jeden element o długości większej niż długość łańcucha, tak aby ostatni element w tablicy był znakiem końca NUL. Liczbę całkowitą można przekazać jako drugi argument, który pozwala określić rozmiar tablicy, jeśli nie należy używać długości ciągu znaków .

... co oznacza to tworzenie char[7], ale strcpy() będzie próbował skopiować NULL terminator na sznurku, więc jeśli maksymalna „nazwa węzła” długość wynosi siedem znaków, trzeba się do char[8] trzymaj numer NULL, ale możesz uciec z użyciem memcpy(array[i], nodes[i], 7) zamiast strcpy().

Zamiast tego prawdopodobnie najbezpieczniej będzie użyć numeru create_string_buffer(8).

3

W tej linii:

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

Ty tworząc pojedynczy bufor 7 bajtów, a następnie próbuje go używać do przechowywania 4 wskaźniki znaków (które prawdopodobnie 4 bajtów każdy), a następnie także kopiowania 4 8-bajtowe ciągi znaków w przypadkowych adresach, na które może wskazywać. Musisz przydzielić bufor dla każdego ciągu, a także przydzielić tablicę wskaźników. Coś takiego:

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