Adresse von einer Liste.

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Hallo, ich möchte Bilddaten von einer dll auswerten (Farberkennung) lassen.

Code: Alles auswählen

data = f.read(intsize)
Mit ctype kann ich schon einen Ganzzahlwert an eine dll übergeben und zurückgeben lassen.

Wie Bekomme ich jetzt die Adresse(Pointer) oben von der Liste "data".

Danke.

Gruss
BlackJack

@funkheld: `data` ist keine Liste sondern eine Zeichenkette (Typ `str`). Du kannst da zum Beispiel mit `ctypes.create_string_buffer()` ein Objekt erstellen, das ein C-`char`-Array repräsentiert.
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Na gut.

Aber in dieser data habe ich jetzt $4000 ByteDaten drin.
Diese Adresse möchte ich jetzt rausfinden um drauf zugreifen zu können in der dll.

ctypes soll mir nur die Adresse/Wert übergeben an die dll mehr nicht, das klappt ja auch schon.

Danke.

Gruss
BlackJack

@funkheld: Was genau spricht jetzt gegen `ctypes.create_string_buffer()`?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

in Python
- Länge des Strings ermitteln (solltest Du machen, da read() weniger zurückliefern kann und Du in C möglicherweise einen Pufferüberlauf erzeugst)
- Stringpuffer erstellen mit create_string_buffer(dein_string, Länge)

Damit hast Du ein char-Array und die Größe des Arrays, die Du der C-Funktion übergeben kannst. In C greifst Du mittels Startadresse des Arrays und Pointerarithmetik (max. +Länge) auf die Bytes zu.

Falls die C-Funktion nicht von Dir ist, musst Du Dich genau an die Vorgaben halten, dh. die Parameter so vorbereiten, dass die C-Funktion damit arbeiten kann. ctypes bietet hierfür alle nötigen Typen bis hin zu struct (Klasse Structure).
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Was genau spricht jetzt gegen `ctypes.create_string_buffer()`?
Weil es eigentlich kein String ist, sondern eine Binärdatei, das bringt mich mit dem String ein bisschen durcheinander.

Aber ist wohl so in Python.

Gruss
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Sieht schon gut aus.
Bekomme das bei print raus :
<ctypes.c_char_Array_256 object at 0x00AA3800>

Ist das die Adresse?
Wie kann ich jetzt mit Python probehalber von dieser Adresse einen Wert holen.

Gruss

Code: Alles auswählen

import os
from ctypes import *

laenge=os.path.getsize("cpc.bin")

print
print laenge," byte lesen"
print

f=open("cpc.bin", "rb") 
s = f.read(laenge) 

for j in s:
    print ord(j)
    
p=create_string_buffer(s,laenge)    

print p
BlackJack

@funkheld: Python kennt als Datentyp keine Speicheradressen bzw. Zeiger sondern nur Objekte. Du hast da ein Objekt das in der "Python-Welt" ein `char`-Array in C repräsentiert. Der Typ implementiert den Indexzugriff. An das erste Byte kommst Du zum Beispiel mit ``p[0]``.

Das Objekt repräsentiert übrigens ein Array und nicht einen Zeiger auf ein Array! Wenn man eine C-Funktion hat, die einen Zeiger erwartet, weiss ich aus dem Kopf jetzt gerade nicht, ob `ctypes` das beim Aufruf selber umsetzt, oder ob man explizit `ctypes.byref()` verwenden muss.
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Was ist das denn : at 0x00AA3800

Wer kann da jetzt weiterhelfen für eine Pointeradresse/Zeiger.

Danke.

Gruss
BlackJack

@funkheld: Das ist die Adresse an der die Datenstruktur für die Implementierung des Python-Objekts liegt -- nicht die Adresse des C-Arrays was durch das Objekt repräsentiert wird. Ist ausserdem ein Implementierungsdetail. Die "Zahl" muss da nicht stehen in der `repr()`-Zeichenkette von einem Objekt.

Ich habe doch schon gesagt was Du machen musst um bei einem Funktionsaufruf einen Zeiger übergeben zu können.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Was erwartet die C-Funktion denn? Poste bitte mal die Parameterliste. Ansonsten stochern wir nur in Vermutungen rum. In Python selbst ist die Adressgeschichte völlig uninteressant und wird vor dem Anwender versteckt.
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Ist in Purebasic.
Funktionieren alle drei.

Hier die dll von Purebasic :

Code: Alles auswählen

Global wertl.l,wertf.f

ProcedureCDLL.l multl(varl.l)
  wertl.l = varl.l * 5
  ProcedureReturn wertl.l
EndProcedure

ProcedureCDLL.f multf(varf.f)
  wertf.f = varf.f * 5.4
  ProcedureReturn wertf.f
EndProcedure

ProcedureCDLL.l adresse(*adr.l)
  wertl.l = PeekB(*adr+2)
  ProcedureReturn wertl.l
EndProcedure
hier das von Python:

Code: Alles auswählen

import os
from ctypes import *

dl = cdll.LoadLibrary("pydll.dll")

laenge=os.path.getsize("cpc.bin")

print
print laenge," byte lesen"
print

f=open("cpc.bin", "rb") 
s = f.read(laenge) 

for j in s:
    print ord(j)
    
p=create_string_buffer(s,laenge)  
pp = pointer(p)

bb=dl.adresse(pp)

print bb

bb=dl.adresse(pp) kommt -51
bb=dl.adresse(p) kommt auch -51

bei s[2] liegt der Wert 205 drin bzw bei *adr+2 in der dll von ProcedureCDLL.l adresse(*adr.l) müsste auch 205 rauskommen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ach herje, Du willst eine Funktion, die mit PureBasic erstellt wurde, aufrufen?
Sind mit PureBasic erstellte DLLs denn kompatibel zu C-Bibliotheken? Ist das Maschinencode oder schleppt er da noch einen Interpreterkontext mit? Wie siehts mit der calling convention aus?

Ich kann Dir nur ein simples Bsp. für C geben:

Code: Alles auswählen

#include <stdio.h>

int print_array(char * t, int t_len) {
	int i;

	// mit Pointern
	for (i=0; i<t_len; ++i)
		printf("%c", *(t+i));
	printf("\n");

	// oder Indexzugriff
	for (i=0; i<t_len; ++i)
		printf("%c", t[i]);
	printf("\n");

	return 0;
}
Speichern und als shared lib kompilieren. In Python kannst Du es dann so aufrufen:

Code: Alles auswählen

>>> import ctypes
>>> bla = ctypes.cdll.LoadLibrary("/pfad/zu/lib")
>>> bla.print_array(ctypes.create_string_buffer('hallo'), 5)
hallo
hallo
0
Kannst Du denn andere Funktionen Deiner PureBasic-DLLs mittels ctypes erreichen?
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Jetzt geht es.
Ich muss die Ausgabe in wert.c (c bedeutet in Purebasic unsigned char) ändern, "l" steht für "long".

Code: Alles auswählen

ProcedureCDLL.c adresse(*adr.l)
  wertl.c = PeekB(*adr+2)
  ProcedureReturn wertl.c
EndProcedure
Jetzt ist "print bb" der 67zigsteWert aus dem Array..

Code: Alles auswählen

import os
from ctypes import *

dl = cdll.LoadLibrary("pydll.dll")

laenge=os.path.getsize("cpc.bin")

print
print laenge," byte lesen"
print

f=open("cpc.bin", "rb") 
s = f.read(laenge) 

for j in s:
    print ord(j)
    
pp=pointer(create_string_buffer(s,laenge)) 

bb=dl.adresse(pp,67)

print bb
Kannst Du denn andere Funktionen Deiner PureBasic-DLLs mittels ctypes erreichen?
Die beiden oberen Proceduren von Purebasic, sogar mit float funktionieren wunderbar.

Jupp danke.

gruss
peter
Zuletzt geändert von funkheld am Donnerstag 4. November 2010, 13:25, insgesamt 2-mal geändert.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Schön, dass das geht. PureBasic scheint sich an die C-Konventionen zu halten.

Trotzdem würde ich Dir raten, die Länge des Puffers mit zu übergeben, falls Du mehr mit den Daten in PureBasic vorhast und das Ende des Arrays kennen musst.
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Jup, danke, wird beachtet.

Ich habe jetzt erstmal getestet und gesehen, das es sehr wenig Aufwand ist, die dll in Purebasic zu schreiben und der Aufwand von Python (wenn man es weiss) auch sehr gering ist ,damit umzugehen.

Oben hatte ich auch mal einen Ganzzahl übergeben , eine Float-Zahl und eben einen Zeiger und das alles mit Rückgaben.

Da ich in Purebasic einfach ASM-Code einsetzen kann in Proceduren, ist es sehr schnell gemacht mal eine Superschnelle Routine mit ASM in eine dll zu setzen mit Purebasic.
Gerade bei Bildauswertungen sind solche kleinen ASM-Tools sehr Hilfreich.


Gruss
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Bringt Assembler da heutzutage noch soviel? Die großen Compiler optimieren schon relativ viel, sodass die Vorteile von Assembler dahinschwinden und eigener Assemblercode schnell ungüstiger ist und mehr Instruktionen bzw. Zyklen braucht. Ich weiss nicht wie gut PureBasic hier mitspielt. Die Nachteile bleiben in jedem Falle bestehen.

Wie auch immer, mit NASM kannst Du auch direkt kritische Funktionen in Assembler erstellen und als shared lib linken lassen (ohne Umweg über PureBasic). Der kennt alle möglichen Binärformate, um die calling convention musst Du Dich dann allerdings selber kümmern.

Viel Spaß mit Assembler :twisted:
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Oh man....., natürlich. :D
Wenn ich Grafik auswerte für eine Hinderniserkennung zb mit den MMX-Befehle..., ein traum von Schnelligkeit junge.
Dagegen ist das Tkinter oder wxpython eine Schlaftablette. :D

Du hast wahrscheinlich noch keine test gemacht? :D

Gruss
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ähm steh ich hier auf der Leitung ???

Seit wann kann man Assembler mit einer GUI (Tkinter oder wxpython) vergleichen ???
Mal abgesehen davon das ie einen völlig anderen Zweck erfüllen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
funkheld
User
Beiträge: 258
Registriert: Sonntag 31. Oktober 2010, 09:26

Ich weiss nicht wie gut PureBasic hier mitspielt. Die Nachteile bleiben in jedem Falle bestehen.
Ha,ha...., es gibt keine Nachteile.
Ich nehme nur Purebasic weil ich es besitze und man damit schnell und einfach dll erstellen kann unter anderem mit ASM.
Da kann man sich richtig austoben. :D

So sieht zb eine Routine aus, die ich dann auch als dll kompilieren kann:

Code: Alles auswählen

ProcedureCDLL.l MyTest()
    MOV eax, 45
    ProcedureReturn  
 EndProcedure
Antworten