"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

c++ (arduino): gegenseitiger aufruf von memberfunktionen

wergor 15.10.2014 - 17:22 3460 9
Posts

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4095
ich habe in meinem arduino projekt die klassen SerialHandler und Device:
SerialHandler - sendet und empfängt nachrichten über die serielle verbindung, ruft memberfunktionen von der Device- instanz auf.
Device - macht sachen (z.b. bewegen von schrittmotoren).

die instanzen der beiden klassen sind global definiert. damit SerialHandler auf Device zugreifen kann, ist der header Device.h in SerialHandler.h included und die Device instanz mit #extern deklariert. wenn ein kommando hereinkommt, ruft SerialHandler die entsprechende memberfunktion der Device klasse auf, wartet bis die fertig ist und sendet dann eine antwort.

soweit funktioniert das auch wunderbar. jetzt will ich aber dass die SerialHandler nicht auf die Device klasse warten muss, deshalb soll die Device klasse nach getanener arbeit von sich aus das senden der antwort veranlassen. damit die Device klasse auf member der SerialHandler klasse zugreifen kann, muss ich in der Device.h die SerialHandler.h includen und mit #extern die SerialHandler instanz deklarieren. da spielt aber der compiler nicht mit (Device includes SerialHandler includes Device includes...).

die einfachste lösung wäre Device selbst die antworten schicken zu lassen, aber ich würde das lieber den SerialHandler machen lassen. gibts da eine möglichkeit?

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11338
Zitat von wergor
jetzt will ich aber dass die SerialHandler nicht auf die Device klasse warten muss, deshalb soll die Device klasse nach getanener arbeit von sich aus das senden der antwort veranlassen.

Das Senden der Antwort in der anderen Klasse zu machen ist nicht schwierig, aber das "dass SerialHandler nicht auf Device warten muss" - wie hast du dir das vorgestellt? Du musst ja trotzdem die Funktion aufrufen, und die kommt erst zurück wenn sie fertig ist.

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4095
dafür habe ich eine library.
Die funktionen die serialhandler aufruft setzen nur neue ziele / parameter für die schrittmotoren. Im main loop wird eine funktion run() aufgerufen die die schrittmotoren einen schritt vor oder zurück gehen lässt wenns nötig ist und dann returned, dadurch ist der code nicht durch warten auf das device blockiert.
Code: C
void loop()
{
serialHandler.parseInput();

device.run(); 
}

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11338
Ich weiß nicht wie das bei Arduino ist (das baut ja ein bisserl Logik um deine Funktionen drumherum), aber in "normalem" C++ gibts .h und .cpp Files. Du kannst in jedem .cpp jedes .h #includen und es gibt keine endlosen Zyklen. Was ist überhaupt "#extern"?

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4095
ich bin mir gerade nicht sicher dass das problem durch endlose zyklen entsteht. wenn ich in der Device.h die SerialHander.h include, wirft der compiler folgende fehlermeldung:
Code:
Device.h:In file included from
Device.cpp:from
SerialHandler.h:17: error: 'Device' does not name a type
Error compiling
zeile 17 der SerialHandler.h:
Code:
extern Device device;

@extern: (natürlich ohne #, sry) http://stackoverflow.com/a/10422050
Zitat
This comes in useful when you have global variables. You declare the existence of global variables in a header, so that each source file that includes the header knows about it, but you only need to “define” it once in one of your source files.

To clarify, using extern int x; tells the compiler that an object of type int called x exists somewhere. It's not the compilers job to know where it exists, it just needs to know the type and name so it knows how to use it. Once all of the source files have been compiled, the linker will resolve all of the references of x to the one definition that it finds in one of the compiled source files. For it to work, the definition of the x variable needs to have what's called “external linkage”, which basically means that it needs to be declared outside of a function (at what's usually called “the file scope”) and without the static keyword.

Hansmaulwurf

u wot m8?
Avatar
Registered: Apr 2005
Location: VBG
Posts: 5639
edit:
Sorry, jetzt hab ichs überissen, und kann nix beitragen :bash:
Bearbeitet von Hansmaulwurf am 16.10.2014, 22:44

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4095
Zitat von Hansmaulwurf
@wergor : Warum schreibst nicht einfach eine memberfunktion für "Device" die Parameter vom Serial übernehmen kann? Dann brauchst nicht im Kreis linken.
ich habe mehrere device klassen. die SerialHandler klasse soll die commands an die jeweils richtigen devices weitergeben.


Zitat von Hansmaulwurf
edit:
Sorry, jetzt hab ichs überissen, und kann nix beitragen :bash:
np :)

PuhBär

Schau ned so genau
Avatar
Registered: Sep 2002
Location: .
Posts: 1228
Forwarddeclaration evtl? Weiss nicht ob das dann mit extern funktioniert.

Würde im Serialhandler.h einfach ein "class Device;" hinschreiben, anstatt Device.h zu inkludieren.

Solange du Serialhandler nicht als Member in Device brauchst, kann der incomplete type von Device als Parameter für eine Funktion verwendet werden. Inkludieren kannst du Serialhandler.h dann im Device.cpp.

Paxi

Overclocking Team Member
Avatar
Registered: Oct 2009
Location: Wien
Posts: 389
Forwarddeclaration würde eben nur funktionieren sofern man noch keine Methode der Klasse aufrufen will bzw generell nur solange man nur auf Pointer der Klasse referenziert weil sonst der Compiler die exakte Größe kennen muss, was er bei einer Forwarddeclaration noch nicht tut.

Ich würde zwar jetzt kein Geld darauf wetten aber ich bin mir relativ sicher, dass es für den Compiler kein Problem darstellt, wenn zwei Header sich gegenseitig includen und man einen davon included. Wichtig ist jedenfalls nur, dass beide Header einen Header guard haben. Also sowas wie:
Code: C
#ifndef HEADER_H
#define HEADER_H

// code
#endif

Sofern möglich sollte man Header aber immer erst im .cpp inkludieren, wie bereits gesagt wurde.

Bzg extern: Es spricht nichts dagegen extern in diesem Zusammenhang zu verwenden, sofern man auf eine existierende Variable in einer anderen Translation Unit referenziert.
Ich persönlich bevorzuge aber eher solche Konstrukte:

Code: C
// Header
static Instance* GiveMeTheInstance();

// Cpp
static Instance* GiveMeTheInstance() {
         static Instance instance;
         return &instance;
}

Sowas habe ich in C++ schon ein paar mal verwendet (auch wenn ich da sowas wie Singletons eher vermeide), wird wohl in C auch so funktionieren.

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4095
danke für die antworten!
forward declaration direkt vor den extern statements in beiden header files hat das problem gelöst.
Code:
class SerialHandler;
extern SerialHandler serialHandler;

Zitat von Paxi
Ich würde zwar jetzt kein Geld darauf wetten aber ich bin mir relativ sicher, dass es für den Compiler kein Problem darstellt, wenn zwei Header sich gegenseitig includen und man einen davon included. Wichtig ist jedenfalls nur, dass beide Header einen Header guard haben. Also sowas wie:
Code: C
#ifndef HEADER_H
#define HEADER_H

// code
#endif
header guards hatte ich schon drin.

Zitat von Paxi
Sofern möglich sollte man Header aber immer erst im .cpp inkludieren, wie bereits gesagt wurde.
das klingt nach einer guten idee :) werde ich mir noch genauer anschauen.
Bearbeitet von wergor am 17.10.2014, 17:01
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz