void Pointer als Rückgabewert einer Funktion

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
astloch
User
Beiträge: 8
Registriert: Dienstag 16. Oktober 2012, 14:12

Grüß Gott zusammen.
Ich habe auf der Suche nach meinem Problem keine vernünftige Lösung gefunden und wende mich jetzt damit an dieses tolle Forum.

Aus eine Box die Werte eines Sensors einliest möchte ich die Werte wieder rausbekommen. In der dll der Box sind verschiedene Funktionen zum Auslesen der Daten und eine davon bereitet mir Kopfzerbrechen.

Mein Problem sieht folgendermaßen aus:
Diese Funktion liefert einen void Pointer auf einen Bereich in einem Arrays. In dem Array stehen Datensätze die aus dem Speicher der Box kopiert wurden. Der Zeiger zeigt auf einen bestimmten Abschnitt in dem Feld um mir zB. Position, Triggerzeitpunkt oder das Statuswort zu geben.

Ich weiß aber nicht wie ich an die Adresse, geschweige denn den den Wert auf den der Pointer zeigt bekomme.

Ich hoffe ihr könnt mir helfen und bedanke mich schonmal.

LG
astloch

PS: hier ist der C-Code dazu.

Code: Alles auswählen

void *field;
unsigned char udp_data[]; //da stehen die Werte aus dem Speicher drin

/* read timestamp from data packet */
CheckError(EIB7GetDataFieldPtr(eib, udp_data, enc_axis + 1,
               EIB7_PDF_Timestamp, &field, &sz));
EncoderData.Timestamp = *(unsigned long *)field;
und hier mein Pythonversuch:

Code: Alles auswählen

class EncData(Structure):   #hier sollen später mal die Daten rein.
        _fields_ = [("position", c_longlong),
                    ("status", c_ushort),
                    ("TriggerCounter",c_ushort),
                    ("Timestamp",c_ulong)]
                    
EncoderData = EncData()
eib7_global   = c_int(0)
trig_cnt      = c_int(0x0001)
status        = c_int(0x0002)
pos_dat       = c_int(0x0004)    #Datenelement fuer die Achse
timestamp     = c_int(0x0008)
array_val_ptr = c_ubyte * 200
udp_data      = array_val_ptr()
enc_1         = c_int(num_of_entry+1)         #Achse der EIB
size          = c_ulong()
ref_fifo      = pointer(fifo)
sz            = c_ulong()
field         = c_void_p()
      
bib.EIB7GetDataFieldPtr(eib_handler,udp_data,eib7_global,trig_cnt, byref(field),byref(sz))
Zuletzt geändert von Anonymous am Mittwoch 17. Oktober 2012, 10:16, insgesamt 1-mal geändert.
Grund: Quelltext in C- und Python-Code-Tags gesetzt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Indem du dir den Rückgabewert der Funktion anschaust. Du kannst mit dem ``restype``-Attribut den Rückgabewert der Funktion als ``c_void_p`` definieren und dann bekommst du genau das als Rückgabewert der Funktion. Eigentlich ist das in der ctypes-Dokumentation ganz gut beschrieben, und die scheinst du dir ja angeschaut zu haben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
astloch
User
Beiträge: 8
Registriert: Dienstag 16. Oktober 2012, 14:12

danke für die Antwort. Aber der eigentliche Rückgabwert der Funktion ist einfach nur ein int-Wert der auf den Status des Funktionsaufrufes rückschließen lässt.

Den Rückgabewert den ich beschrieben habe, bekomme ich indem die Funktion dem void-Zeiger (void *field) den ich ihr übergebe eine Adresse zuweist.

Ich habe in dem ursprünglichen C-Code den &-Operator vergessen:

Code: Alles auswählen

CheckError(EIB7GetDataFieldPtr(eib, udp_data, enc_axis + 1,
               EIB7_PDF_Timestamp, & &field, &sz));
EncoderData.Timestamp = *(unsigned long *)field;

nach Funktionsaufruf soll field auf die Adress im Array zeigen.

momentan bekomme ich folges:

Code: Alles auswählen

trigger:            2 c_long(1) c_void_p(45484864)
Ist das jetzt die Adresse oder was hat das alles zu bedeuten?
LG
astloch
User
Beiträge: 8
Registriert: Dienstag 16. Oktober 2012, 14:12

wobei der letzte Ausdruck der ausschlaggebende ist:

Code: Alles auswählen

c_void_p(45484918)
BlackJack

@astloch: Ja das ist die Adresse. Da müsstet Du jetzt noch das machen, was Du auch im C-Code siehst: casten und dereferenzieren.

Edit: Beispiel um ein Array mit zwei Zeichen/Bytes als 16-Bit-Ganzzahl zu interpretieren:

Code: Alles auswählen

In [59]: import ctypes as ct

In [60]: a = ct.c_char_p('\x01\x02')

In [61]: hex(ct.cast(a, ct.POINTER(ct.c_uint16))[0])
Out[61]: '0x201'
astloch
User
Beiträge: 8
Registriert: Dienstag 16. Oktober 2012, 14:12

Ok. Danke.
Das hat funktioniert. Ist das auch sicher die Adresse auf die der Zeiger zeigt und nicht die Adresse vom Zeiger selbst?
Ich bekomme nämlich immer den Wert 0 zurück und hoffe das es vielleicht daran liegt. Ich will nämlich nicht das ganze Programm nochmal überarbeiten.

Wofür ist eigentlich der Index nach dem Cast?

Schöne Grüße
astloch
BlackJack

@astloch: Das ist der Wert vom Zeiger und der Wert eines Zeigers ist die Adresse auf die er verweist.

Der Indexzugriff ist zum dereferenzieren. Durch den `cast()` bekommt man ja nur einen Zeiger eines anderen Typs, man muss dann ja aber noch vom Zeiger auf den Wert kommen auf den er zeigt.
astloch
User
Beiträge: 8
Registriert: Dienstag 16. Oktober 2012, 14:12

Hallo BlackJack,
Aber dann hätte der Zeiger ja den Wert 0, achso, bekommt der Zeiger durch das Casten den Wert 0???. Irgendwie bin ich jetzt total verwirrt.
Stimmt das jetzt was da bei mir rauskommt und der Fehler ist im Programm zu suchen, oder habe ich das Casten und Dereferenzieren falsch gemacht.
Ich bin weiterhin über jede Hilfe dankbar.

Ich habe hier nochmal den Code gepostet und was ich als Ausgabe erhalte.

Code: Alles auswählen

bib.EIB7GetDataFieldPtr(eib_handler,udp_data,eib7_global,trig_cnt, byref(field),byref(sz))
    print "trigger: %12d"%sz.value, trig_cnt, field 
    x = cast(field,POINTER(c_ushort))
    print "x:",x    
    print "Wert von x:", x[0]
Ausgabe:

Code: Alles auswählen

trigger:            2 c_long(1) c_void_p(98179128)
x: <__main__.LP_c_ushort object at 0x05DD4030>
Wert von x: 0
BlackJack

@astloch: Welchen Wert der Zeiger nach dem `cast()` hat sieht man doch überhaupt nicht. Das ist ja aus Python-Sicht der hier: ``<__main__.LP_c_ushort object at 0x05DD4030>``. Aus C-Sicht ist es exakt der selbe Wert, den auch der void-Zeiger vorher aus C-Sicht hatte, denn ein cast in C ändert nichts am Wert, sondern nur den Typ.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Warum castest du denn im C-Code auf einen "unsigned long *" und im Python-Code auf "unsigned short *"?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten