Moin @ all,
gitb es in Python eine Möglichekeit, einen Zeiger auf einen Zeiger zu erzeugen ?
Danke schonmal im Vorraus !
Gruß,
M
Zeiger auf Zeiger ?
Also, ich möchte von Python aus auf eine C Funktion zugreifen, die in einer DLL gespeichert ist.
Dank des "cType" Moduls und einigen Threads hier im Forum funktionieren die meisten anderen Funktionen aus der DLL auch ganz hervorragend, aber die Aktuelle Fkt will halt einen Zeiger auf einen Zeiger von mir als Argument übergeben bekommen:
Die Übergabe mittels ctypes und
klappt auch bei anderen Funkionen, nur wie ich den Zeiger auf den Zeiger auf den Charakter realisieren soll bin ich überfordert 
Ich habe schon probiert, der DLL einen Zeiger auf ein Array mit chars zu übergeben, aber dann erhalte ich eine "Access Violation":
Soweit ich weiß, erwartet die DLL ein zweidimensionales Array, auf das sie mittels des "char**" zugreifen kann.
Gibt es für mich nicht irgendeine Möglichkeit, von Python aus eine solche Struktur an C zu übergeben ?
Gruß,
M[/code]
Dank des "cType" Moduls und einigen Threads hier im Forum funktionieren die meisten anderen Funktionen aus der DLL auch ganz hervorragend, aber die Aktuelle Fkt will halt einen Zeiger auf einen Zeiger von mir als Argument übergeben bekommen:
Code: Alles auswählen
STATUS Report_i(unsigned short id_us, unsigned char number_puc, char** entry_ppc)
Code: Alles auswählen
pointer (c_ubyte(number_puc))

Ich habe schon probiert, der DLL einen Zeiger auf ein Array mit chars zu übergeben, aber dann erhalte ich eine "Access Violation":
Code: Alles auswählen
from ctypes import *
from array import array
lib = cdll.LoadLibrary("d:\meine.dll")
var1 = c_ubyte()
var2 = array('c',' '*256)
lib.Report_i(c_ubyte(10),pointer(var1),var2.buffer_info()[0])
Gibt es für mich nicht irgendeine Möglichkeit, von Python aus eine solche Struktur an C zu übergeben ?
Gruß,
M[/code]
Ich glaube das Array Modul passt hier besser. Du musst dann wohl einen Array von chars erzeugen...
Das wird nicht helfen. Was er braucht ist ein Array mit Zeigern wo jeder Zeiger wiederum auf ein Array mit Zeichen verweist.ProgChild hat geschrieben:Ich glaube das Array Modul passt hier besser. Du musst dann wohl einen Array von chars erzeugen...
Warum wird das nicht helfen. Ich dachte an so was...BlackJack hat geschrieben:Das wird nicht helfen. Was er braucht ist ein Array mit Zeigern wo jeder Zeiger wiederum auf ein Array mit Zeichen verweist.ProgChild hat geschrieben:Ich glaube das Array Modul passt hier besser. Du musst dann wohl einen Array von chars erzeugen...
Code: Alles auswählen
>>> import array
>>> import struct
>>>
>>> a = array.array('c', 'Text')
>>> (address,t) = a.buffer_info()
>>> address
134906760
>>> struct.pack('P',address)
'\x88\x83\n\x08'
Hallo !
Vielen Dank für die Hilfe !
Ich hab mal n bisschen rumprobiert und es nun auf folgende Art und Weise gelöst:
Funktioniert auch, nur weiß ich nicht, ob das eine so "saubere" Lösung ist...
Vielen Dank auf jeden Fall nochmal!
Gruß,
M
Vielen Dank für die Hilfe !
Ich hab mal n bisschen rumprobiert und es nun auf folgende Art und Weise gelöst:
Code: Alles auswählen
from array import array
from ctypes import *
libc = cdll.LoadLibrary('d:\meine.dll')
Var1 = c_ubyte()
Var2 = array('c',' '*256)
Var2_zeig = c_ulong(Var2.buffer_info()[0])
libc.Report_i(c_ushort(10),pointer(Var1),pointer(Var2_zeig))
return [int(Var1.value),Var2.tostring()]
Vielen Dank auf jeden Fall nochmal!
Gruß,
M
Ich denke das hier ist "sauberer":
Und das C Programm zum Testen:
Code: Alles auswählen
from ctypes import cdll, c_char_p, c_uint, ARRAY, POINTER
dll = cdll.LoadLibrary('./char_array.so')
test = dll.test
test.argtypes = (c_uint, POINTER(c_char_p))
test.restype = None
def c_string_array(strings):
char_p_array = ARRAY(c_char_p, len(strings))()
for i, string in enumerate(strings):
char_p_array[i] = string
return char_p_array
data = ('spam', 'eggs', 'vikings')
test(len(data), c_string_array(data))
Code: Alles auswählen
/* gcc -o char_array.so -shared char_array.c */
#include <stdio.h>
void test(unsigned int count, const char **strings)
{
int i;
for (i = 0; i < count; ++i) {
puts(strings[i]);
}
}
Moin,
nach ner kleinen Pause hab ichs mal getestet
Diese Lösung ist natürlich sehr elegant, funktioniert aber leider nicht.
Nach der letzten Zeile (Ausführen von Test) bekomme ich eine "Access Violation" von Windows zurück...
Kann das daran liegen, daß die C - Bibliothek das Array nicht einliest, sondern versucht, darauf zu schreiben ?
Gruß,
m
nach ner kleinen Pause hab ichs mal getestet

Code: Alles auswählen
from ctypes import *
dll = cdll.LoadLibrary("d:\meine.dll")
test = dll.Report_i
test .argtypes = (POINTER(c_ubyte),POINTER(c_char_p))
number = pointer(c_ubyte())
pointerarray = ARRAY(c_char_p,64)() # das zu erwartende Array ist max. 64 Zeichen lang
test(number,pointerarray)
Nach der letzten Zeile (Ausführen von Test) bekomme ich eine "Access Violation" von Windows zurück...
Kann das daran liegen, daß die C - Bibliothek das Array nicht einliest, sondern versucht, darauf zu schreiben ?
Gruß,
m
Arrays in c sind konstante Startadressen. Desweiteren lassen sich in c Arrays nicht übergeben, man hat lediglich die Möglichkeit einen Pointer auf die Startadresse des Arrays oder die Adresse selbst zu übergeben. Demzufolge arbeitet man immer mit dem Original. Wenn die Funktion also irgendwo etwas in das Array schreibt kann es schon sein, dass du auf Speicherbereiche zugreifen willst, für die du keine Berechtigung hast.
Frage Nummer 1: Ist der erste Parameter wirklich ein Pointer auf ein Byte?TelefonMann hat geschrieben:Code: Alles auswählen
from ctypes import * dll = cdll.LoadLibrary("d:\meine.dll") test = dll.Report_i test .argtypes = (POINTER(c_ubyte),POINTER(c_char_p)) number = pointer(c_ubyte()) pointerarray = ARRAY(c_char_p,64)() # das zu erwartende Array ist max. 64 Zeichen lang test(number,pointerarray)
Frage Nummer 2: Der Kommentar ist verwirrend: Das ist kein Array von Zeichen sondern ein Array von Zeigern auf Zeichen. Also bekommst Du dort maximal 64 Pointer zurück!?
Moin,
ich glaube ich weiß mittlerweile wo der Fehler liegt, aber zunächst erstmal ein paar Antworten
1.) Ja, definitiv. Der Header der C-Funktion sieht so aus:
(war oben falsch, sri!)
Die Funktion schreibt mir in das Array eine Anzahl Bytes und übergibt mir in id_us, wieviele Zeichen sie ins Array geschrieben hat.
2.) Richtig, natürlich. Ich bekomme maximal 64 Pointer zurück.
Der Fehler, warum ich eine Access Violation bekomme liegt glaube ich darin, daß ich das array erst "initialisieren" muss, da sonst die C Funktion versucht auf einen Pointer zuzugreifen, der nach "None" zeigt, oder ?
Gruß,
M
ich glaube ich weiß mittlerweile wo der Fehler liegt, aber zunächst erstmal ein paar Antworten

1.) Ja, definitiv. Der Header der C-Funktion sieht so aus:
Code: Alles auswählen
int Report_i(unsigned short id_us,unsigned char* number_puc, char** entry_ppc)
Die Funktion schreibt mir in das Array eine Anzahl Bytes und übergibt mir in id_us, wieviele Zeichen sie ins Array geschrieben hat.
2.) Richtig, natürlich. Ich bekomme maximal 64 Pointer zurück.
Der Fehler, warum ich eine Access Violation bekomme liegt glaube ich darin, daß ich das array erst "initialisieren" muss, da sonst die C Funktion versucht auf einen Pointer zuzugreifen, der nach "None" zeigt, oder ?
Gruß,
M
Blödsinn, erst denken, dann tippen:TelefonMann hat geschrieben: Die Funktion schreibt mir in das Array eine Anzahl Bytes und übergibt mir in id_us, wieviele Zeichen sie ins Array geschrieben hat.
natürlich schreibt mir die Funktion die Anzahl der Bytes in "number_puc"
Ich habe jetzt mal den umgekehrten Weg von meinem ersten Testprogramm probiert:
Und die dazugehörige C-Bibliothek:
Das funktioniert so ganz gut.
Das Array initialisierst Du bei `ctypes` schon in gewisser Weise. `None` ist der Wert den `ctypes` als NULL-Pointer verwendet, d.h. die C-Bibliothek sieht dort NULL-Pointer. Wenn sie auf so einen zugreifen möchte, dann kracht es natürlich, aber ich dachte sie schreibt die Zeiger in das Array hinein und liest sie nicht aus!?
Code: Alles auswählen
from ctypes import cdll, c_char_p, c_uint, ARRAY, POINTER, c_byte, byref
dll = cdll.LoadLibrary('./char_array.so')
test = dll.test
test.argtypes = (c_uint, POINTER(c_char_p))
test.restype = None
test2 = dll.test2
test2.argtypes = (POINTER(c_byte), POINTER(c_char_p))
test2.restype = None
def c_string_array(strings):
char_p_array = ARRAY(c_char_p, len(strings))()
for i, string in enumerate(strings):
char_p_array[i] = string
return char_p_array
data = ('spam', 'eggs', 'vikings')
test(len(data), c_string_array(data))
result = ARRAY(c_char_p, 10)() # Result is max. 10 pointers.
result_count = c_byte()
test2(byref(result_count), result)
for i in xrange(result_count.value):
print result[i]
Code: Alles auswählen
/* gcc -o char_array.so -shared char_array.c */
#include <stdio.h>
static char *foo[3] = { "foo", "bar", "baz" };
void test(unsigned int count, const char **strings)
{
int i;
for (i = 0; i < count; ++i) {
puts(strings[i]);
}
}
void test2(unsigned char *count, char **strings)
{
int i;
for (i = 0; i < 3; ++i) {
strings[i] = foo[i];
}
*count = i;
}
Das Array initialisierst Du bei `ctypes` schon in gewisser Weise. `None` ist der Wert den `ctypes` als NULL-Pointer verwendet, d.h. die C-Bibliothek sieht dort NULL-Pointer. Wenn sie auf so einen zugreifen möchte, dann kracht es natürlich, aber ich dachte sie schreibt die Zeiger in das Array hinein und liest sie nicht aus!?