Array mit verschiedenen Datentypen

Gast #2532801
Lesenswert?

Hi,


also ich habe ne Idee aber bei der Umsetzung bin ich mir net ganz sicher 
ob es da nicht bessere gibt?
Ich würde gern einen Array haben, der Daten verschiedener Datentypen 
(int,float..) halten kann.

Evtl. wird es mi dem Code deutlicher was ich will:
1
typedef struct
2
{
3
    int8_t a[3];
4
    uint16_t b[3];
5
    float c[3];
6
} ComplexDataType;
1
// Template beispiel
2

3
template <class DATA_1,uint8_t size_1, class DATA_2,uint8_t size_2 , class DATA_3, uint8_t size_3>
4
class ComplexDataType
5
{
6
    DATA_1 a[size_1];
7
    DATA_2 b[size_2];
8
    DATA_3 c[size_3];
9

10
};

Das ist noch nicht ganz meine Lösung, da ich die Größen der Arrays 
varrieren will und zudem es sein kann dass es stat float mal uint32_t 
sein soll.
Ich dachte an sowas wie Template-Klassen (s. Beispiel).
Das ganze soll letzendlich auf einem Controller laufen.

Gibt es alternativen für mein Problem oder bedenken für die Template 
lösung?

Gruß
GoldenEyes
Gast #2532815
Lesenswert?

Stell Dir vor, jemand kommt zu Dir, hält Dir eine Rohrzange und einen 
Maulschlüssel entgegen und wünscht von Dir zu wissen, was er verwenden 
soll.
Da würdest auch sagen: Kommt darauf an, wofür!
Gast #2532840
Lesenswert?

Srry.


Also ich habe Daten von Sensoren (SensorData) und Steuerdaten 
(ControlData), die aus verschiedenen Datentypen bestehen sollen damit 
ich diese an die Regelung wie folgt übergeben kann:
1
+
2

3
// in Control.h
4

5
...
6
void control(ComplexDataType ControlData, ComplexDataType SensorData)
7
{
8
..
9
if( XY) controlXY(ControlData.DATA_1, SensorData.DATA_1);
10
else if( ZZ) controlZZ(ControlData.DATA_2, SensorData.DATA_2);
11
..
12
}
13
...
14

15

16
// in main
17
Control::Control(ControlData,SensorData);
Je nach dem welche Regelung (hier mit XY und ZZ bez.) gewünscht ist 
werden die entsprechenden Daten übergeben!

Hoffe jetzt etwas klarheit verschafft zu haben!
Gast #2532854
Lesenswert?

Hm. Nun haben wir noch mehr Teile der Lösung. Aber immer noch keine 
Angaben zum Problem.

Ich habe aber auch keine Lust nochmal nachzubohren.
Klare und verständliche Darstellung von Problemen ist Teil der Kunst und 
kein überflüssiges Übel.

Um Dich nicht ganz ohne was zu lassen werfe ich mal das Stichwort 
"unions" in den Raum. Pass auf das es Dich nicht beisst. :-)

Viel Erfolg.
Gast #2532870
Lesenswert?

Ja, also das Problem habe ich schon im ersten Beitrag geschildert!

Ich habe mich für die Templatevariante entschieden, dennoch Danke ich 
dir für deine Bemühungen.

Unions sind mir nicht fremd, aber bringen tuht mir das nicht(zum. wüsste 
ich nicht wie).


Gruß
GoldenEyes
#2532927
Lesenswert?

Die Lösung für dein Problem lautet höchst wahrscheinlich: Basisklasse + 
entsprechende Ableitungen dafür.

In den meisten Fällen, in denen du in C++ versucht bist zu schreiben

  if( Typ der Daten ist nada )
    mach was

  else if( Typ der Daten ist juhu )
    mach was

  else if( Typ der Daten ist schnutzelbrutz )
    mach aber sowas von ganz was anderem


lautet die C++ Lösung: Polymorphismus mit virtuellen Funktionen.
Gast #2532946
Lesenswert?

1
template <class DATA_1,uint8_t size_1, class DATA_2,uint8_t size_2 , class DATA_3, uint8_t size_3>
2
class ComplexDataType
3
{ public:
4
    DATA_1 a[size_1];
5
    DATA_2 b[size_2];
6
    DATA_3 c[size_3];
7

8
};
9

10
// egal wo ich den Complexen daten type benötige
11

12

13
ComplexDataType <int, 3, int, 3, int ,3> TEST1;
14
ComplexDataType <int, 3, float, 2, float ,3> TEST2;
15
ComplexDataType <unsigned int, 2, float, 1, unsigned char ,3> TEST3;

Um nochmal zu meinem Template zurück zukommen;
Also so könnte ich mir jede beliebige (fast) Kombination von Daten 
erstellen oder übersehe ich etwas???
Mir geht es nur um den DatenType, die Funktion sind bei mir als Template 
realisiert, die jeweils die grundtypen unterstüzen!
Gruß
Gast #2532975
Lesenswert?

goldeneyes1987 schrieb:
> Mir geht es nur um den DatenType, die Funktion sind bei mir als Template
> realisiert, die jeweils die grundtypen unterstüzen!
> Gruß

Also das ganze könnte sogar so aussehen:
1
void winkel_regler (ComplexDataType* a);
2
void abstands_regler (ComplexDataType* a);

Jetzt könnten die Funktionen jeden beliebigen Datentype übergeben 
bekommen;
Intern nutzt die Funktion nur das von TEST1 was sie benötigt!
Beispiel:
1
ComplexDataType* <int, 3, int, 3, int ,1> TEST1;
2
...
3
/*
4
in TEST1 werden jetzt winkelpositionen(3Achsen), winkelgeschwindigkeiten(3Achsen) und abstand zu einem gegenstand gespeichert.
5
*/
6
...
7
winkel_regler(TEST1);
8
abstands_regler(TEST1);
9
..
10
// jeder Regler weiss worauf er zugreifen muss.
11
// so kann ich alles Zustandsinformation zentral in einer Instanz speichern!
Gast #2533003
Lesenswert?

goldeneyes1987 schrieb:
> Ich würde gern einen Array haben, der Daten verschiedener Datentypen
> (int,float..) halten kann.
>
> Evtl. wird es mi dem Code deutlicher was ich will:
> typedef struct
> {
>     int8_t a[3];
>     uint16_t b[3];
>     float c[3];
> } ComplexDataType;

nun ja, was du hast ist eben kein Array, das verschiedene Datentypen
halten kann, sondern schlicht eine Struktur voller Arrays. Läuft
irgendwie darauf hinaus, dass du eine "allwissende" Struktur
erschaffen willst, von denen die jeweiligen Regler oder was du da baust,
ein Stückchen auswerten.

Mein erster Gedanke war in Richtung echter heterogener Arrays, wie sie
jede moderne Skriptsprache kennt. Zum Beispiel in Python
s = filter(lambda x: type(x)==str, ["1",1.0,1])
oder
s = ["1",1.0,1].reject {|x| x.class != String} in Ruby

In C gibt es das so nicht. Was auch gut ist.
Nachbauen lässt sich das dennoch irgendwie über einen Container
aus void* Zeigern. std::vector<void*> vielleicht. Oder vector von
smart pointern. So elegant wie bei Skriptsprachen wird es ganz sicher 
nicht ;)
Gast #2533009
Lesenswert?

Daniel schrieb:
> Nachbauen lässt sich das dennoch irgendwie über einen Container
> aus void* Zeigern. std::vector<void*> vielleicht. Oder vector von
> smart pointern. So elegant wie bei Skriptsprachen wird es ganz sicher
> nicht ;)

Ja genau, und in C++ kann man void* mit hilfe von Templates ersetzen.
Gast #2533038
Lesenswert?

goldeneyes1987 schrieb:
> Ja genau, und in C++ kann man void* mit hilfe von Templates ersetzen

die "Magie" der templates liegt eher in compile time Modifizierungen
des Codes, um diesen die Schnittstellen typsicher zu machen.
void* kann hingegen zu runtime zu allen erdenklichen Mittel greifen.
Wie auch immer. Ich habe nochmal deine Postings gelesen und glaube
die sauberste Lösung wäre die vom Karl Heinz. Sauber im Sinne möglichst
wenig Querabhängigkeiten. Wenn alles in der grossen Datenstruktur 
steckt,
weiß dein ReglerX was er benötigt, du wirst aber wahrscheinlich in einem
Jahr dieses Wissen nicht mehr haben ;) Auch grosse switch/case 
respektive
if/else Kaskaden müssen zentral gepflegt werden, wobei in meinen Augen
das immer noch besser ist, als allen Reglern alle Daten zu geben.
Bei gemeinsamen Abstammung können andere Regler ins System untergejübelt
werden, wenn die Schnittstelle aus virtuellen Funktionen besteht.
#2533099
Lesenswert?

goldeneyes1987 schrieb:
> goldeneyes1987 schrieb:
>> Mir geht es nur um den DatenType, die Funktion sind bei mir als Template
>> realisiert, die jeweils die grundtypen unterstüzen!
>> Gruß
>
> Also das ganze könnte sogar so aussehen:
>
1
> 
2
> void winkel_regler (ComplexDataType* a);
3
> void abstands_regler (ComplexDataType* a);
4
>
>
> Jetzt könnten die Funktionen jeden beliebigen Datentype übergeben
> bekommen;
> Intern nutzt die Funktion nur das von TEST1 was sie benötigt!

Na, dann mach mal.
Wenn du es hinbekommen hast, zeig mal. Das würde ich gerne sehen, wie du 
untempletierte Funktionen schreibst, die ein nicht weiter ausgeführtes 
Template als Argument nehmen und da auch noch sauber drauf zugreifen.
#2533104
Lesenswert?

> winkel_regler(TEST1);
> abstands_regler(TEST1);
> ..
> // jeder Regler weiss worauf er zugreifen muss.
> // so kann ich alles Zustandsinformation zentral in einer Instanz
> speichern!

Hier liegt schon der erste Denkfehler in einer OOP Welt.

Es gibt keine Funktion winkel_regler

Wohl aber gibt es ein Regler Objekt, instanziiert von einer Regler 
Klasse, welche selber weiß, welche Daten (+Datentypen) es benötigt und 
daher die entsprechenden Member besitzt.

Wenn du OOP ernst nimmst, dann gibt es keine Funktionen mehr. Es gibt 
nur noch Objekte und diese Objekte
* kümmern sich um sich selbst
  d.h. das Objektt selbst hält die Daten, die es zur Arbeit benötigt
* verstehen Befehle
  die Befehle sind die Memberfunktionen.

Solange du nicht von der Sichtweise abrückst, dass es da einen Satz 
Daten gibt und du schreibst Funktionen, die irgendwie diese Daten 
manipulieren, bist du noch nicht in OOP angekommen. Das ist kein 
Vorwurf. Gerade Leute, die mit funktionalen Programmiersprachen groß 
geworden sind, tun sich da schwer, die Denkweise umzustellen. Ich hab 
fast 3 Jahre gebraucht, bis ich aufgehört habe 'C mit Klassen' zu 
programmieren und den Umstieg nach OOP komplett und mit allen 
Konsequenzen vollzogen habe.
Gast #2533135
Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du es hinbekommen hast, zeig mal. Das würde ich gerne sehen, wie du
> untempletierte Funktionen schreibst, die ein nicht weiter ausgeführtes
> Template als Argument nehmen und da auch noch sauber drauf zugreifen.

Du hast natrülich recht, das geht so nicht!
Aber so:
1
emplate <class DATATYPE_1, uint8_t size_1,  class DATATYPE_2, uint8_t size_2, class DATATYPE_3, uint8_t size_3>
2
class ComplexData
3
{
4
public:
5
  DATATYPE_1   angle[size_1];
6
  DATATYPE_2   angle_velocity[size_2];
7
  DATATYPE_3   position[size_3];
8
};
9

10
class Controller
11
{  template <class DATATYPE_1, uint8_t size_1,  class DATATYPE_2, uint8_t size_2, class DATATYPE_3, uint8_t size_3>
12
  void angle_control(ComplexData <DATATYPE_1,size_1,DATATYPE_2,size_2,DATATYPE_3,size_3> *c);
13
    template <class DATATYPE_1, uint8_t size_1,  class DATATYPE_2, uint8_t size_2, class DATATYPE_3, uint8_t size_3>
14
  void position_control(ComplexData <DATATYPE_1,size_1,DATATYPE_2,size_2,DATATYPE_3,size_3> *c);
15

16
};
17

18
template <class DATATYPE_1, uint8_t size_1,  class DATATYPE_2, uint8_t size_2, class DATATYPE_3, uint8_t size_3>
19
void Controller::angle_control(ComplexData <DATATYPE_1,size_1,DATATYPE_2,size_2,DATATYPE_3,size_3> *c)
20
{
21
  // integration
22
  c->angle[0] += c->angle_velocity*0.02;
23
  .....
24
}

Zudem stimme ich auch dem zweiten Beitrag zu.
Ich sehe auch das die Lösung wie ich sie hier oben beschrieben habe, bei 
einem wachsenden Datentype (angle, angle_velocity, position, 
accelertion, trans_velocity, ...) einen risen "Rattenschwanz" mit sich 
bringen würde!
Ich habe momentan aber keine bessere oder überhaupt ne Lösung die 
letzendlich das löst!?!
Gast #2533160
Lesenswert?

Dessen benutzung würde wie folgt funktionieren:
1
// main.cpp
2

3
ComplexData <int, 2, int, 2,float, 3> *TEST;
4
Controller myTestController;
5
myTestController.angle_control(TEST); // angle_control() mus als public dekl. sein


Oder hat das ganze einen knackpunkt den ich übersehe???
Gast #2533204
Lesenswert?

Als die Software besteht aus mehreren Modulen, mindestens :

Sensormodul
Steuerungsmodul
Zustandsmodul
Regelungsmodul

Das Sensormodul liefert mir einen Vektor mit Informationen, dessen Größe 
und Datentype variieren kann.
Das Zustandsmodul nimmt sich diesen Vektor und errechnet daraus 
Zustandsgrößen, dessen Größe und Datentype nicht gleich sind.
Das Regelungsmodul bekommt einen Vektor vom Steuerungsmoudl sowie die 
Zustandsgrößen.

Eine "Schnittstellen"-Klasse CotrolRequest erhält alle Daten und reicht 
sie an die jeweiligen speziischen Regler weiter.

Bis jetzt hatt ich das so geregelt:
1
myControlRequest.control(inputs, states, WINKELREGLER);
also ich muss immer als benutzer sagen welchen Regler ich gerade 
ansprechen will da der Zustandsvektor (states) einem bestimmen datentype 
hat, was ich aber nicht will.

Ich weiss nicht ob dies das Erklärt was ich versuche zu übermitteln?
Aber ich hoffe es!
Gast #2533515
Lesenswert?

Also bin zu dem schluß gekommen eine etwas pragmatischere Lösung 
anzustreben:
1
// Prinzipiell gibt es 4 Verschiedene Komplexe Datenstrukturen
2

3
class Inputs{
4
public:
5
         uint16_t rc_command[5];
6
         // vorerst nur rc_command, wird sich aber ändern!
7
};
8

9
class Sensor{
10
public:
11
   int16_t angle_rate[3];
12
   int16_t accelerration[3];
13
         // vorerst .....
14
};
15
class States{
16
public:
17
   float angle[3];
18
   int16_t angle_rate[3];
19
   int16_t accelerration[3];
20
         // vorerst .....
21
};
22

23
class Output{
24
public:
25
         uint16_t output[5];
26
         // vorerst .....
27
};
28

29

30
class MyController{
31
public:
32
  void angle_control(Inputs* a, Sensor* b, States* c);
33
        void position_control(Inputs* a, Sensor* b, States* c);
34
};
35

36
void MyController::angle_control(Inputs* a, Sensor* b, States* c)
37
{
38
    b->angle[0] += b->angle_velocity[0]*0.02;
39
}

Jetzt können sich die Datentypen (Inputs,Sensor und co.) beliebig ändern 
und ohne Einfluß auf andere Member-Funktionen. Da z.B die Funktion 
angle_velocity(..) immer nur auf "angle" und "angle_velocity" zugreift.

Hat jemand dennoch einen Einwand warum dies so nicht gemacht werden 
solte (im Kontext mit µC oder anderer Natur) ??

Gruß
GoldenEyes

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren