www.mikrocontroller.net

Forum: PC-Programmierung Verstehe Fehlermeldung von Visual Studio C++ 2005 nicht


Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,

ich hab eine Klasse "Thread" in der ich alle Funktionen zum starten bzw. 
stoppen eines Threads benötigt werden. Diese Klasse habe ich nun 
abgeleitet, so dass ich in der Klasse "CSerialPortChild" auf die 
"virtuelle Methode" mit dem Namen "void ThreadFunction(void*);" 
zugreifen kann.

Headerdatei "CSerialPortChild.h":
typedef struct Srecv STrecv;
struct Srecv 
{  
  char receive[1024];
  int len;
};

class CSerialPortChild: public CSerialPort, public Thread
{                             
public:
  
  STrecv recv;

  // contruction and destruction
  CSerialPortChild();
  ~CSerialPortChild();
  void ThreadFunction(void*);

protected:
    

};

#endif

Quelldatei "CSerialPortChild.cpp"
CSerialPortChild::CSerialPortChild():CSerialPort()
{

}


CSerialPortChild::~CSerialPortChild()
{

}


void CSerialPortChild::ThreadFunction(void* ptr)
{
  Srecv *precv= (Srecv*)ptr;

  while(true)
  {
    precv->len = 0;


  }

}

Nun möchte ich in der Methode "ThreadFunction" auf die Variablen 
"receive" und "len" zugreifen. Wenn ich es so mache, wie oben gezeigt 
dann erscheint folgende Fehlermeldung:

Unbehandelte Ausnahme bei 0x00411b35 in ComTerm.exe: 0xC0000005: 
Zugriffsverletzung beim Schreiben an Position 0xcdcdd1cd.


Aufrufliste:
-ComTerm.exe!CSerialPortChild::ThreadFunction(void * ptr=0xcdcdcdcd) 
Zeile 28 + 0x3 Bytes  C++
-ComTerm.exe!Thread::my_Thread(void * para=0x0031beb0)  Zeile 51 + 0x15 
Bytes  C++

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tiger schrieb:

> -ComTerm.exe!CSerialPortChild::ThreadFunction(void * ptr=0xcdcdcdcd)

                                                           **********

Du übergibst eine ungültige Adresse.
Der Fehler liegt also beim Aufrufer.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da fehlt noch einiges an Quelltext.
Wo ist der Start des Threads? Was wird da übergeben?

Außerdem sollte in einer Klasse, in der mindestens eine virtuelle
Methode ist, IMMER der Destruktor auch virtuell sein.
Hat damit nichts zu tun, aber fiel mir so auf.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Da fehlt noch einiges an Quelltext.
> Wo ist der Start des Threads? Was wird da übergeben?
>
> Außerdem sollte in einer Klasse, in der mindestens eine virtuelle
> Methode ist, IMMER der Destruktor auch virtuell sein.
> Hat damit nichts zu tun, aber fiel mir so auf.

Weiters:
Wenn eine Funktion in der Basisklasse virtual ist, sollte man die 
gleichnamige Funktion in der abgeleiten Klasse ebenfalls explizit 
virtual machen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, wobei das nur zur Klarheit ist; virtual ist sie sowieso.

Autor: Tiger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab den gesamten Quellcode hochgeladen. Ich weiss da nicht mehr 
weiter.
Für jede Hilfe sag ich schonmal vielen Dank!

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bin raus, ich kann kein rar

Autor: Tiger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab die Dateien nun mit Zip gepackt.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich es so mache, wie oben gezeigt
> dann erscheint folgende Fehlermeldung:
>
> Unbehandelte Ausnahme bei 0x00411b35 in ComTerm.exe: 0xC0000005:
> Zugriffsverletzung beim Schreiben an Position 0xcdcdd1cd.

...

Wenn Du das im Debugger laufen lässt, dann siehst Du auch, wie die 
Funktion mit welchen Parametern aufgerufen wurde. Wie schon von Karl 
Heinz beschrieben, ist der Pointer, der "ThreadFunction" übergeben 
wurde, nicht initialisiert.


Der von Dir gepostete Code ist übrigens unvollständig, es fehlt 
"SerialPortChild.cpp".

- auch im ZIP-Archiv.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du brauchst doch nur am Call Stack zurückgehen und dir ansehen, wer die 
ThreadFunction aufruft und welches Argument er ihr mitgibt. Die nächste 
Frage ist dann, wo kommt dieses Argument her und warum wurde es nie 
initialisiert.

Wenn du dich mit Threads beschäftigst, solltest du solche Dinge schon 
können. Ansonsten treiben dich die schwierigeren Dinge bei Threading in 
den Wahnsinn.

Autor: Tiger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hab sie ausversehen vergessen mit reinzunehmen.

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wie müsste ich den Pointer von der Methode "ThreadFunction" 
initialisieren?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ist das die SerialPortChild.cpp?
Glaube, mein Zipper ist kaputt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tiger schrieb:
> Und wie müsste ich den Pointer von der Methode "ThreadFunction"
> initialisieren?


Je nachdem was du eigentlich machen willst.

Im Moment wird die Threadfunction aufgerufen und ihr der Callbackpointer 
mitgegeben m_callback. Der kriegt aber nie einen Wert (ausser NULL). Und 
damit geht dann der Zugriff precv->len = 0; mächtig in die Hose.

Da dein Stack Trace einen Pointer Wert von 0xcdcdcdcd zeigt, in dem von 
dir geposteten Code m_callback aber auf 0 initialisiert wird und ich bei 
mir im Debugger den Pointer auch tatsächlich als 0x000000 sehe, gehe ich 
davon aus, dass du den Code seit deinem ersten Post verändert hast.


Mach dich mit deinem Debugger vertraut! Der ist der Helfer in der Not. 
Ohne mit ihm umgehen zu können, brauchst du nicht weitermachen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo ist denn nun der Start des Threads? Dort kann man doch einen
Parameter angeben (void* oder LPVOID oder sowas), der an die
Threadfunktion durchgereicht wird. Und genau da müsstest du
die Adresse deiner Struct übergeben.

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für eure Hilfe. Ich weiss nicht wo ich wie und was übergeben muss.
Ich bin jetzt total durcheinander.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich weiss nicht wo ich wie und was übergeben muss.
Müssen tust du gar nichts.
Du bist der Boss, du entscheidest, welche Daten wo in welche Funktion 
übergeben werden. Aber kein Mensch schreibt dir vor, was du tun musst.


Lass mich raten.

Code von irgendwo her kopiert. Nicht duchgeschaut und auch noch keinen 
Versuch gemacht das zu verstehen.

So funktioniert Programmieren nicht. Klar kann man Code von irgendwo her 
kopieren. Aber man muss ihn auch verstehen. Und das mindeste ist es, im 
Debugger einmal duchzusteppen.

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein dem ist nicht so. Ich hab mal vor einiger Zeit mit einem 
Echtzeitbetriebssystem zu tun gehabt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tiger schrieb:
> Nein dem ist nicht so. Ich hab mal vor einiger Zeit mit einem
> Echtzeitbetriebssystem zu tun gehabt.

Jetzt bin ich verwirrt.

Du schreibst einen relativ banalen 100-Zeiler und blickst dann selbst 
nicht mehr durch, warum eine Funktion einen ungültigen Pointer bekommt?

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

DWORD WINAPI Thread::my_Thread(void* para)
{
    Thread* pthis=(Thread*)para;
  int t;
  if(pthis!=NULL)
  {
    pthis->ThreadFunction(pthis->m_callback);
    t=9;
    return 0;
  }
  return -1;
}


Was ist hier bitte schön falsch daran? Sorry, wenn ich euch damit nerve.
Ich hab nur ganz normal um Hilfe gebeten.

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Thread starte ich damit:
hThread = CreateThread(NULL, Thread_STACK_SIZE, my_Thread, this, 0, &dwThreadID);

Wo müsste ich da noch einen Pointer übergeben?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, und wenn ich das richtig sehe, ist der vierte Parameter
(bei dir: this) das, was als void-Parameter an die
Threadfunktion weitergereicht wird.
Darin castet du das in einen Zeiger auf eine struct, was natürlich
schief geht.

Wenn ich jetzt nicht falsch liege, müsstest du als 4. Parameter die
Adresse der gewünschten struct angeben.

Was hattest du mit dem this an dieser Stelle vor?

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Klaus Wachtler,

danke für den Rat. Allerdings weiss die Klasse Thread ja nicht, dass die 
Klasse CSerialPortChild eine Struktur besitzt. Wie kann man trotz all 
dem eine Adresse übergeben?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu müsste man wissen, wie deine Objekte zusammenhängen und wie
alles zusammen spielen soll. Eigentlich müsstest du das wissen;
ich habe gerade keine besondere Lust, das aus einem
undokumentierten Quelltext zu rekonstruieren.

Rein technisch geht es notfalls über eine globale Variable, die
jemand vorher setzt (sicher der schlechteste Weg), oder irgendwelche
get- oder set-Methoden, über die Thread das rechtzeitig erfährt.

Autor: UserX (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler (mfgkw) schrieb:
>bin raus, ich kann kein rar

In welchem Jahrhundert lebst du denn?
Rar gibt's doch heutzutage für alle Systeme.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt es sicher, aber ist auf meinem Rechner nicht drauf.
Und ehrlich gesagt muß ich auch nicht jedes obskure Datenformat
handhaben, solange es ein paar verbreitete und frei zugängliche
Formate gibt. RAR ist meines Wissens nicht frei (zumindest das
Komprimieren).
Warum nicht ZIP?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tiger schrieb:
>
> 
> DWORD WINAPI Thread::my_Thread(void* para)
> {
>     Thread* pthis=(Thread*)para;
>   int t;
>   if(pthis!=NULL)
>   {
>     pthis->ThreadFunction(pthis->m_callback);
>     t=9;
>     return 0;
>   }
>   return -1;
> }
> 
> 
>
> Was ist hier bitte schön falsch daran?

Da ist gar nichts falsch daran.

pthis->m_callback wird übergeben.

Aber pthis->m_callback wird nie auf einen Wert gesetzt!
Das würde über einen Aufruf von SetCallback gemacht, aber die Funktion 
wird nie aufgerufen.

Schuss ins Blaue:

CSerialPortChild::CSerialPortChild():CSerialPort()
{
  SetThreadCallBack( &this->recv );
}

Aber eigentlich müsstest DU das wissen. Du hast es ja designed.

Autor: Tiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab auch mein Fehler entdeckt. So funktioniert es:
CSerialPortChild::CSerialPortChild():Thread()
{
  recv.len = 0;
  SetThreadCallBack((void*)&recv );
}


Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.