Frage zu konvertierung von ctype in Python Typ
@snow: Ja. Wobei man da üblicherweise in der Bibliothek eine Funktion für schreibt. Mit einem einfachen `free()` ist es ja nicht getan, man muss ja alle Zeichenketten in dem Array auch freigeben.
Zwei Hinweise hab ich noch bezüglich der VLAs und Deinem kurzen Codebsp.:
Wenn Du das plattformübergreifend halten willst und später mit dem MS-C Compiler übersetzen musst, fliegen Dir die VLAs um die Ohren. Der MS-Compiler ist auf C89 hängengeblieben und Du musst dann alle VLAs mit _alloca umschreiben. Das ist sehr nervig beim Refactoring.
Da Dir die Geschwindigkeit so wichtig ist, warum übergibst Du nicht `text` mit Offset und Länge dem `setInsert`? Das char cur[] ist imho ein überflüssige Kopieraktion.
Wenn Du das plattformübergreifend halten willst und später mit dem MS-C Compiler übersetzen musst, fliegen Dir die VLAs um die Ohren. Der MS-Compiler ist auf C89 hängengeblieben und Du musst dann alle VLAs mit _alloca umschreiben. Das ist sehr nervig beim Refactoring.
Da Dir die Geschwindigkeit so wichtig ist, warum übergibst Du nicht `text` mit Offset und Länge dem `setInsert`? Das char cur[] ist imho ein überflüssige Kopieraktion.
Ich arbeite gerade nur auf Linux, aber ich wollte es auf jeden Fall auch unter Windows weiterhin lauffähig halten. Hatte eigentlich vor mit gcc für windows die Bibliothek zu erzeugen. Wird das ebenfalls zu Problemen führen/ geht das garnicht/ oder gibt das keine Probleme?
Das andere werd ich mal ändern, danke.
Das andere werd ich mal ändern, danke.
Ich habe das gerade mal geändert, dass ich nach dem auslesen, den Speicherplatz mit der Methode frei mache:
und bekomme dann folgenden Fehler:
Dann habe ich mal das in C probiert und habe den selben Fehler bekommen:
Bei einem AUfruf an der Funktion im C Code wird das DArray ganz normal gecleared, aber beim zweiten mal crasht es dann wie im Python Code. Weiß jemand den Grund dafür?
Code: Alles auswählen
pointer = self.lib.tokenize(c_char_p(text))
....
self.lib.dArrayFree(pointer)
Code: Alles auswählen
*** Error in `/usr/bin/python': double free or corruption (out): 0x0000000002e84440 ***
Code: Alles auswählen
DArray *result = tokenize("$hallo wer @ist da");
.....
dArrayFree(result);
dArrayFree(result);
Naja, `free()` sollte üblicherweise auch nur exakt einmal pro Zeiger aufgerufen werden. Danach kann man nicht mehr davon ausgehen, dass der Zeiger noch gültig ist und somit kracht es beim zweiten Aufruf dann entsprechend.
Du sprichst hier von "gecleared". Ich würde bei "free" im Namen einer Funktion aber erwarten, dass da mehr gemacht wird, als nur den Inhalt zu leeren. Wie gesagt: "free" meint eher, dass das gebundene Objekt komplett abgeräumt werden soll, weil man es nicht mehr benutzen muss und somit der vom Objekt genutzte Speicher wieder freigegeben weden kann.
Du sprichst hier von "gecleared". Ich würde bei "free" im Namen einer Funktion aber erwarten, dass da mehr gemacht wird, als nur den Inhalt zu leeren. Wie gesagt: "free" meint eher, dass das gebundene Objekt komplett abgeräumt werden soll, weil man es nicht mehr benutzen muss und somit der vom Objekt genutzte Speicher wieder freigegeben weden kann.
Ja aber im obigen Python Code rufe ich die free Methode ja nur einmal auf und es crasht genauso wie wenn ich es 2 mal im C Code aufrufen würde. Aber ich hab im Python Code wirklich nur einmal versucht den Speicher dafür zu leeren. Deswegen die Frage : Wieso crasht der Python Code als wenn ich 2 mal free aufgerufen hätte?
@snow: Kannst Du eingrenzen *wo* der Crash auftritt? Also vor oder nach dem Aufruf Deiner `dArrayFree()`-Funktion?
Ansonsten wäre ein minimales aber lauffähiges Beispiel praktisch, an dem man das nachvollziehen kann.
Ansonsten wäre ein minimales aber lauffähiges Beispiel praktisch, an dem man das nachvollziehen kann.
Der Crash tritt direkt beim Aufruf der dArrayFree Funktion auf.
Der gesamte Code ist dieser hier:
Was vielleicht noch interessant ist, ist die C Funktion für den Free, aber ich glaube nicht dass es daran liegt, weil im C Code funktioniert sie:
Der gesamte Code ist dieser hier:
Code: Alles auswählen
class DArray(Structure):
_fields_ = [("length", c_uint),
("capacity", c_uint),
("elems", POINTER(c_char_p))]
class RaschLexer():
def __init__(self):
self.lib = CDLL(./libSnowEdit.so")
self.lib.tokenize.argtypes = [c_char_p]
self.lib.tokenize.restype = POINTER(DArray)
self.lib.dArrayFree.argtypes = [POINTER(DArray)]
def getVariables(self, text):
variables = set([])
pointer = self.lib.tokenize(c_char_p(text))
ret = pointer.contents
for i in range(ret.length):
variables.update([ret.elems[i]])
self.lib.dArrayFree(pointer)
return variables
Code: Alles auswählen
void dArrayFree(DArray *arr) {
if (arr != NULL) {
if (arr->elems != NULL){
uint i;
for (i = 0; i < arr->length; i++) {
free(arr->elems[i]);
}
free(arr->elems);
}
free(arr);
}
}
@snow: So auf Anhieb fällt mir eigentlich nur auf, dass der Rückgabetyp von der Funktion nicht auf `None` gesetzt wird. Damit ist nicht 100%ig ausgeschlossen, dass nach der Funktion nicht ein C-``int`` vom Aufrufstapel als Rückgabewert entfernt wird, der dann dort fehlt und zu Folgefehlern führt.
Die Klasse macht übrigens keinen Sinn. Der gemeinsame Zustand sind einfach nur ein paar Funktionen die man genauso gut auf Modulebene hätte definieren können und dann halt eine Lexer-/Parsefunktion. Ich hätte das so geschrieben (natürlich ungetestet):
Die Klasse macht übrigens keinen Sinn. Der gemeinsame Zustand sind einfach nur ein paar Funktionen die man genauso gut auf Modulebene hätte definieren können und dann halt eine Lexer-/Parsefunktion. Ich hätte das so geschrieben (natürlich ungetestet):
Code: Alles auswählen
from itertools import islice
class DArray(Structure):
_fields_ = [
('length', c_uint),
('capacity', c_uint),
('elems', POINTER(c_char_p))
]
D_ARRAY_P = POINTER(DArray)
lib_snow_edit = CDLL('./libSnowEdit.so')
_tokenize = lib_snow_edit.tokenize
_tokenize.argtypes = [c_char_p]
_tokenize.restype = D_ARRAY_P
_d_array_free = lib_snow_edit.dArrayFree
_d_array_free.argtypes = [D_ARRAY_P]
_d_array_free.restype = None
def rasch_parse(text):
d_array_p = _tokenize(text)
try:
d_array = d_array_p.contents
return set(islice(d_array, d_array.length))
finally:
_d_array_free(d_array_p)
@snow: erstens ist die c-Calling-Konvention dass der Aufrufer sich um die Parameter auf dem Stack kümmert und zweitens wird bei der üblichen 64-bit-Calling-Konvention gar keine Parameter mehr auf den Stack gelegt.
Memory-Leaks können sehr schwer zu finden sein. Ohne vollständigen Code kann man da kaum Tipps geben.
Daher sind Programmiersprachen, die sich darum kümmern auch so bequem
Memory-Leaks können sehr schwer zu finden sein. Ohne vollständigen Code kann man da kaum Tipps geben.
Daher sind Programmiersprachen, die sich darum kümmern auch so bequem
@jerch: In meinem C-Testprogramm für die C Lib :
Darray wurde erzeugt. Adresse: 0x865090
Darray elems wurde erzeugt. Adresse: 0x8650b0
Darray wurde erzeugt. Adresse: 0x865140
Darray elems wurde erzeugt. Adresse: 0x865160
Darray elems freed. Adresse: 0x8650b0
Darray freed. Adresse: 0x865090
Darray elems freed. Adresse: 0x865160
Darray freed. Adresse: 0x865140
Und im Python Code nach eingabe der ersten Variablen:
Darray wurde erzeugt. Adresse: 0x1a9a6d0
Darray elems wurde erzeugt. Adresse: 0x1d0e3b0
Darray wurde erzeugt. Adresse: 0x1d083e0
Darray elems wurde erzeugt. Adresse: 0x1d0e4a0
Darray elems freed. Adresse: 0x1d0e3b0
Darray freed. Adresse: 0x1a9a6d0
@Sirius3 aber immerhin gibt es in C/C++ ja Programme wie valgrind die einem dabei helfen diese Memeory-Leaks zu finden. Aber wär schon was, wenn es eine Sprache gibt die so bequem wie Python ist und gleichzeitig so performant wie C. \dreamoff ^^
Darray wurde erzeugt. Adresse: 0x865090
Darray elems wurde erzeugt. Adresse: 0x8650b0
Darray wurde erzeugt. Adresse: 0x865140
Darray elems wurde erzeugt. Adresse: 0x865160
Darray elems freed. Adresse: 0x8650b0
Darray freed. Adresse: 0x865090
Darray elems freed. Adresse: 0x865160
Darray freed. Adresse: 0x865140
Und im Python Code nach eingabe der ersten Variablen:
Darray wurde erzeugt. Adresse: 0x1a9a6d0
Darray elems wurde erzeugt. Adresse: 0x1d0e3b0
Darray wurde erzeugt. Adresse: 0x1d083e0
Darray elems wurde erzeugt. Adresse: 0x1d0e4a0
Darray elems freed. Adresse: 0x1d0e3b0
Darray freed. Adresse: 0x1a9a6d0
@Sirius3 aber immerhin gibt es in C/C++ ja Programme wie valgrind die einem dabei helfen diese Memeory-Leaks zu finden. Aber wär schon was, wenn es eine Sprache gibt die so bequem wie Python ist und gleichzeitig so performant wie C. \dreamoff ^^
Zuletzt geändert von snow am Dienstag 12. November 2013, 21:35, insgesamt 3-mal geändert.
@snow: Ich würde sagen mit raten kommt man hier nicht weiter. Man bräuchte ein minimales Beispiel was jeder nachvollziehen kann, also bei sich selber auf dem Rechner kompilieren und laufen lassen kann, was das Problem aufzeigt.
edit: Ok Fehler ist gelöst xD Habe gerade noch eine Bedingung in die Python Methode gesetzt, dass wenn der Text leer ist, die Methode gar nicht ausgeführt werden soll und einfach ein leeres set zurück gegeben werden soll, mit dem Ziel weniger printouts zu haben. Nachdem ich gerade einfach aus Spaß den free Aufruf nochmal in die Methode gepackt habe ist das Programm auf einmal nicht mehr abgestürzt.
edit2: Nun ist auch der Grund gefunden warum es bei einem leeren String abgestürzt ist.
Da ich vorher nicht in der Methode newDArray den Pointer auf NULL gesetzt habe, wurde natürlich die Adresse auf irgendwas gesetzt. Die Prüfung in der Free Methode konnte natürlich nicht greifen und wollte irgendwo im Nirvana Speicher frei machen. Ich weiß, böser Patzer
Trotzdem danke für eure Hilfe
edit2: Nun ist auch der Grund gefunden warum es bei einem leeren String abgestürzt ist.
Code: Alles auswählen
DArray *newDArray() {
DArray *arr = (DArray*) malloc(sizeof(DArray));
arr->elems = NULL;
arr->length = 0;
arr->capacity = 0;
return arr;
}
void dArrayFree(DArray *arr) {
if (arr != NULL) {
if (arr->elems != NULL){
uint i;
for (i = 0; i < arr->length; i++) {
free(arr->elems[i]);
}
free(arr->elems);
}
free(arr);
}
}
Trotzdem danke für eure Hilfe