Seite 1 von 2
Problem mit Funktionsaufruf in Signal
Verfasst: 11. Juni 2009 23:29
von Darwin
Hallo Forum,
ich arbeite Gerade an einer QT Oberfläche mit ein paar Objekten.
Bei Betätigung dieser werden Signale ausgelöst, welche Methoden aufrufen. In diesen werden wiederum Methoden eines anderen Objektes (mq) ausgeführt.
Bsp:
Code: Alles auswählen
connect(buttonLCDClear, SIGNAL(clicked()), this, SLOT(FunctionLCDClear()));
connect(comboSummer, SIGNAL(currentIndexChanged(int)), this, SLOT(BeeperStateChanged(int)));
Und die Methoden dazu:
Code: Alles auswählen
void Miniterminal::FunctionLCDClear(void)
{ mq.addDataPacket(_terminalID,_receiverID,COMMAND,SET_BEEPER,0,"",STF,ENF);
}
void Miniterminal::BeeperStateChanged(int i)
{
mq.addDataPacket(_terminalID,_receiverID,COMMAND,SET_BEEPER,0,"",STF,ENF);
}
In der Methode addDataPacket von mq werden die Daten in eine Liste eingetragen (das Funktioniert ).
Mein Problem:
Der addDataPacket Aufruf in der FunctionLCDClear-Methode funktioniert (meistens), der addDataPacket Aufruf in der BeeperStateChanged-Methode führt unweigerlich zum Absturz des Programms (xxx.exe hat ein Problem festgestellt und muss beendet werden).
Was mich wundert: Wenn ich den Code der Methode addDataPacket entferne, gibt es keinen Absturz. Wenn ich nach addDataPacket ein Sleep(5 sekunden); einfüge, Dauert es 5 Sekunden bis das Programm abstürzt.
Ich bin echt Ratlos (da noch Anfänger in QT). Vielleicht hat von Euch ja wer einen Einfall.
Wäre echt Dankbar, da ich jetzt schon ein paar Stunden versuche das Problem zu lösen.
Danke,
Michael
EDIT:
QT 4.5.1 / MinGW
WinXP Pro
Gibt es eigentlich in der kostenlosen Version irgendeine Möglichkeit zum Debuggen?
Verfasst: 12. Juni 2009 04:02
von speedy
Code: Alles auswählen
void Miniterminal::BeeperStateChanged(int i)
{
mq.addDataPacket(_terminalID,_receiverID,COMMAND,SET_BEEPER,0,"",STF,ENF);
}
Kennt dieser Aufruf denn die ganzen Variablen?
Sind das globale Variablen in der Klasse?
ja, variablen sind bekannt
Verfasst: 12. Juni 2009 08:52
von Darwin
Hallo!
Ja, die Variablen sind bekannt, der Kompiler meldet keinen Fehler und der Aufruf klappt in der Methode von LCDClear.
Danke,
Michael
Verfasst: 12. Juni 2009 09:02
von franzf
OK, klär uns auf

sind COMMAND, SET_BEEPER, STF und ENF Variablen, Konstanten oder Macros?
Sind die Variablen auch korrekt initialisiert?
Zeig uns mal die Implementierung von
addDataPacket().
Verfasst: 12. Juni 2009 09:05
von solarix
Gibt es eigentlich in der kostenlosen Version irgendeine Möglichkeit zum Debuggen?
Falls du "gdb" (GNU-Debugger) noch nicht hast, einfach ab
http://sourceforge.net/projects/mingw/files dazuinstallieren.
Danach ab der Kommandozeile mit "gdb deinprogramm.exe" laden, mit "run" starten und nach dem Crash mit "where" anschauen, wo das Programm steht.
Ich bin echt Ratlos (da noch Anfänger in QT). Vielleicht hat von Euch ja wer einen Einfall.
Weil der Code nichts auffälliges zeigt, muss der Fehler schon vorher (z.B. unsaubere Pointeroperationen) oder in addDataPacket() produziert worden sein. Es gibt eigentlich folgende zwei Möglichkeiten:
1. mit "gdb" den Fehler suchen
2. das Programm immer weiter reduzieren ( so dass der Crash bleibt) und dann entweder den Fehler selbst erkennen oder hier ein Beispielprojekt posten...
Verfasst: 12. Juni 2009 09:32
von Darwin
Hallo und Danke für Eure bisherigen Beiträge!
COMMAND, SET_BEEPER, STF und ENF sind Markos (zB #define COMMAND 0x02) Diese stehen im MQueue Header (MQueue - Davon wird auch das Objekt mq erzeugt).
Methode addDatapacket:
Code: Alles auswählen
void MQueue::addDataPacket(unsigned char terminalID, unsigned char receiverID, unsigned char commandtype, unsigned char command1, unsigned char command2,const char *data, unsigned char stf, unsigned char enf)
{
// Neuen Link-Zeiger erstellen welcher auf das erste Element zeigt
DPLink *dpl=firstDataPacket;
// So lange weiterspringen bis l auf den letzten vorhandenen Link zeigt
while(dpl->nextDP!= NULL)
{
dpl=dpl->nextDP;
}
// Hier wird das neue Datenpaket eingefügt:
// Neuen DPLink Zeiger erstellen - dies ist der DPLink Zeiger für das neue Datenpaket
DPLink *newDataPacket=new DPLink;
// Nach diesem Link gibt es keinen Link mehr
newDataPacket->nextDP=NULL;
// Hier wird das eigentliche Datenpaket (Zeiger darauf) welcher zum Link gehört erstellt
newDataPacket->dp=new DataPacket(terminalID,receiverID,commandtype,command1,command2,data,stf,enf);
dpl->nextDP=newDataPacket;
// dpl bezieht sich hier noch auf den Link dpl. Da ein neuer Link eingefügt wurde muss der next von dpl nun auf das neue Datenpaket zeigen.
}
Das Struct zu DPLink ( definiert im Header ):
Code: Alles auswählen
struct DPLink
{
DataPacket *dp;
DPLink *nextDP;
};
DPLink *firstDataPacket;
Und die initialisierung im Konstruktor von MQueue:
MQueue::MQueue()
Code: Alles auswählen
{
firstDataPacket=new DPLink; // New Operator liefert Zeiger!
firstDataPacket->dp=NULL; // Mit "->" weil ein Zeiger ist!
firstDataPacket->nextDP=NULL; // Mit "->" ein Zeiger ist
}
Danke, Michael
Verfasst: 12. Juni 2009 09:53
von franzf
So viele (ungetestete) Zeiger, da geht 100% was schief

Ich bin mir fast sicher hier brennt es:
Code: Alles auswählen
DPLink *dpl=firstDataPacket;
while(dpl->nextDP!= NULL)
{
dpl=dpl->nextDP;
}
Irgend eines der nextDP ist nicht NULL aber das referenzierte Objekt ist futsch...
Falls nicht bitte Konstruktor von DataPacket. Oder am besten dem Link von SOlarix folgen und gdb installieren...
Ist firstDataPacket ein globales Objekt oder ein Member deiner Klasse?
Ich denke da solltest du dir ein eigenes Namensschema angewöhnen. Z.B.:
Code: Alles auswählen
int m_Member, mMember, _member; // Member
int s_staticMember, sStaticMember; // static member
usw. dass man auch erkennt was das jetzt gerade ist...
Verfasst: 12. Juni 2009 10:15
von Darwin
Servus,
Variablen die zu einer Klasse gehören beginnen bei mir mit einem Unterstrich _
FirstDataPacket wird im Header angelegt, gleich nach der Deklaration des Structs (siehe oben). Die initialisierung erfolgt im Konstruktor von MQueue (siehe oben)
Ich habe jetzt den code von addDataPacket ausgeblendet und dann Stückchen für Stückchen wieder hinzugefügt. Der Fehler tritt beim erzeugen des Datenpaketes auf:
Code: Alles auswählen
newDataPacket->dp=new DataPacket(terminalID,receiverID,commandtype,command1,command2,data,stf,enf);
Code vom Datapacket-Konstruktor:
Code: Alles auswählen
DataPacket::DataPacket(unsigned char senderID, unsigned char receiverID, unsigned char packetType, unsigned char command1, unsigned char command2, const char *data, unsigned char startFlag, unsigned char endflag)
{
_startFlag=startFlag;
_senderID=senderID;
_receiverID=receiverID;
_packetType=packetType;
_command1=command1;
_command2=command2;
_endFlag=endflag;
delete _data; // Ein mit new reservierter Speicherplatz wird mit delete wieder freigegeben
_data=NULL; // Den Zeiger auf NULL setzen
_dataLenght=strlen(data)+1;
_data=new char[_dataLenght]; // Neuen Speicherplatz reservieren. _data ist der Zeiger darauf
memcpy(_data,data,_dataLenght); // New buffer | Buffer to copy from | Number of characters to copy
}
Und im header:
Code: Alles auswählen
class DataPacket
{
private:
char *_data;
public:
DataPacket(unsigned char senderID, unsigned char receiverID, unsigned char packetType, unsigned char command1, unsigned char command2, const char *data, unsigned char startFlag=0x02, unsigned char endflag=';');
virtual ~DataPacket(void);
private:
unsigned char _startFlag;
unsigned char _senderID;
unsigned char _receiverID;
unsigned char _packetType;
unsigned char _command1;
unsigned char _command2;
unsigned char _dataLenght;
unsigned char _endFlag;
};
Destruktorcode (wird nie aufgerufen):
Mit der Installation vom GDB happerts leider noch. Ich habe die
gdb-6.8-mingw-3.patch sowie die
gdb-6.8-mingw-3.tar.bz2 heruntergeladen, weiss aber nicht wie sie zum installieren sind
Danke, Mike
Verfasst: 12. Juni 2009 10:21
von Darwin
Weitere Eingrenzung:
Der Fehler im Datenpaketkonstruktor hier auf:
delete _data;
Weswegen weiss ich aber nicht, weil das eigentlich so gehen sollte.
Edit: _data ist vom Typ char *, und wird im Datapacket Header deklariert.
Verfasst: 12. Juni 2009 12:32
von Christian81
Sorry aber irgendwie sieht das nach einen kompletten Mischmasch von C und C++ aus... grauenhaft
delete _data ist falsch - wenn schon muss es delkete[] _data heissen. Aber eigentlich wollten wir ja C++ und im speziellen Qt benutzen. QByteArray und ein paar Template-Container wie QList usw. wären nicht schlecht.
Ein virtueller dtor für DataPacket ist auch überflüssig usw.
Und nun zum Problem - ne Idee was überhaupt in _data drin steht zu dem Zeitpunkt wenn es crasht??
Und ab damit nach C++ Grundlagen ...
Verfasst: 12. Juni 2009 12:41
von franzf
Ich würde auch NIE in einer Methode einen übergebenen Pointer deleten. UARGH, viel Spaß beim Debuggen, wenn du den versehentlich später wieder verwenden willst
Und sttat const char* nimm doch einen ordentlichen String (std::string, QString, ..)
Und ein GLOBALES OBJEKT in einem KONSTRUKTOR initialisieren. Du weißt schon was passieren kann, wenn du mehrere Objekte erstellst, und jedesmal dein globales Objekt neu instanziiert wird? Alte Daten futsch.
Wenn globales Objekt, dann bitte brav im zugehörigen *.cpp initialisieren, oder besser, wenn du darauf bestehst dass nur ein Objekt der Klasse existieren darf, per Singleton realisieren.
Und bei so vielen Pointern solltest du schon schauen dass irgend wann schon ein Destruktor aufgerufen wird

Verfasst: 12. Juni 2009 12:57
von solarix
private:
char *_data;
Da würde ausserdem noch ein Copy-CTor und ein Assignment-Operator benötigt.. aber eben: Wie bereits erwähnt mit QString, QByteArray und QLinkedList (dann fällt der ganze "DPLink"-Kram weg) arbeiten.
[EDIT]
gdb-6.8-mingw-3.tar.bz2 heruntergeladen, weiss aber nicht wie sie zum installieren sind
einfach entpacken

.. am besten in das Mingw-Verzeichnis, da hast du erstens die gleiche Struktur (gdb.exe wuerde da also z.B. nach c:\mingw\bin entpackt) und zweitens wirst du ja eh den bin-Pfad in der Windowsumgebung konfiguriert haben..
Verfasst: 12. Juni 2009 13:44
von Darwin
Wow, mit soviel Kritik habe ich jetzt nicht gerechnet, aber man will ja lernen.
>>Sorry aber irgendwie sieht das nach einen kompletten Mischmasch von C und C++ aus... grauenhaft<<
Welche Codeteile meinst Du damit genau?
>>ne Idee was überhaupt in _data drin steht zu dem Zeitpunkt wenn es crasht??<<
Nachdem ich ein Neues Objekt vom Typ DataPacket erzeuge dürfte im Zeiger_data hoffentlich nichts relevantes drinnstehen.
>>Ich würde auch NIE in einer Methode einen übergebenen Pointer deleten.<<
_data ist eine Membervariable der Klasse DataPacket. Das delete wird im Konstruktor aufgerufen.
>>Und ein GLOBALES OBJEKT in einem KONSTRUKTOR initialisieren. Du weißt schon was passieren kann, wenn du mehrere Objekte erstellst, und jedesmal dein globales Objekt neu instanziiert wird? Alte Daten futsch.
Wenn globales Objekt, dann bitte brav im zugehörigen *.cpp initialisieren, oder besser, wenn du darauf bestehst dass nur ein Objekt der Klasse existieren darf, per Singleton realisieren.<<
Welches Objekt meinst du mit dem Globalen??
Verfasst: 12. Juni 2009 13:53
von franzf
Darwin hat geschrieben:Welches Objekt meinst du mit dem Globalen??
Darwin hat geschrieben:FirstDataPacket wird im Header angelegt, gleich nach der Deklaration des Structs (siehe oben). Die initialisierung erfolgt im Konstruktor von MQueue (siehe oben)
Sobald ein Objekt nicht in nem struct, ner Klasse oder sonst einem Codeblock deklariert ist, ist es global, wenns in nem Header steht kann man aus JEDER Datei, die diesen Header includiert, auf GENAU DIESES Objekt zugreifen.
Verfasst: 12. Juni 2009 14:06
von Darwin
Danke für die Information.
Wo ist deiner Meinung nach ein guter Platz zum anlegen der Objekte?
Ich habs im Konstruktor versucht, dann kennt er firstDPLink aber in dem Methoden nicht mehr.
Zwecks zugriff: firstDPLink ist Private und nicht static. Wie soll man da darauf zugreifen können?