mikrocontroller.net

Forum: Compiler & IDEs Umgang mit globalen Datenstrukturen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Moin,

auch mein Hobby Code soll sauber sein. Bei einem größeren Projekt mit 
einer Wetterstation für den F429, die auch noch 3 externe Sensoren 
bedient und ein extra Anzeige Display gibt es bei mir eine größere 
globale Struktur, in der etliche Wetter-Werte liegen, viele davon auch 
noch als Arrays of struct, da 5 Tage stundenweise gespeichert werden. 
Deswegen, damit das Ganze mit __packed in einem Rutsch per Funk an einen 
PC übertragen werden kann. Der Trümmer ist rund 4k gross, global 
external im main.h deklariert und in main.c implementiert, liegt per 
Linker Direktive im residenten Batt-gepufferten BKRAM drin, nahezu alle 
Routinen greifen darauf zu aus den ca 9 .c Files. Die einen füllen ihn, 
andere holen sich für die LCD Grafik alles da raus.

Nur.... ist das im Standard C so usus? Dass Routinen einfach sich das 
was rauspicken was sie brauchen, ganz ohne Funktionsparameter? Jede 
Routine kann ja alles verändern was sie will. main.h ist von allen 
Modulen aus sichtbar.

Wie ist da eine saubere Lösung? Einzelne Werte aus dem Struct als Zeiger 
übergeben? Ist natürlich deutlich mehr Aufwand, dem uC dürfte es egal 
sein, der Lesbarkeit und Wartbarkeit des Codes aber nicht.

Ok, C++... Klassen und gekapselte Daten aber das kann ich leider nicht, 
ging bisher ohne auch.

Wie macht ihr das?

Christian

: Bearbeitet durch User
Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst in der main getter und setter implentieren und die Struktur in 
der main.c definieren. Dadurch haben externe module einen definierten 
Zugriff.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Christian J. schrieb:
> Jede
> Routine kann ja alles verändern was sie will.

Ja, kann sie.

Daher liegt es an dir (als Programmierer) dieser Versuchung zu 
widerstehen.

> Einzelne Werte aus dem Struct als Zeiger
> übergeben?

Beim Zeiger ändert sich nichts an der Problematik des Änderns.

I.A. sollten die Funktionen nur (Zugriff auf) so viel Daten bekommen, 
wie sie auch brauchen.

structs kann man auch by-value übergeben. (4k auf Mikrocontroller ist 
blöd)
Daher gelten da ja auch etwas andere Regeln: globale Variablen sind ok.

Im Übrigen hast du bei GUI meist auch mehrere globale struct.

Autor: Egon D. (egon_d)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Christian J. schrieb:

> Nur.... ist das im Standard C so usus? Dass Routinen
> einfach sich das was rauspicken was sie brauchen,
> ganz ohne Funktionsparameter? Jede Routine kann ja
> alles verändern was sie will. main.h ist von allen
> Modulen aus sichtbar.

Kann man machen.
Hat aber bekanntermaßen den Nachteil, dass man i.d.R.
an vielen verstreuten Stellen etwas ändern muss, wenn
sich diese zentrale Datenstruktur ändert.


> Ok, C++... Klassen und gekapselte Daten aber das
> kann ich leider nicht, ging bisher ohne auch.

Heute eine weitere Folge aus der Serie: "Das kannst
auch Du" :)


> Wie macht ihr das?

Unabhängig von der Sprache - Kapseln: Zugriff auf die
Daten konsequent NUR über Getter und Setter, NIEMALS
direkt auf die Variablen. (Letztlich ist das -- die
Kapselung -- auch der entscheidende Trick an der OOP.)

Speziell in C: Ich weiss nicht, ob ich das Lehrbuch
richtig verstanden habe, aber "static" sollte hier
weiterhelfen. Die Variablen sowie alle Getter und
Setter kommen in einen eigenen Quelltext; die Variablen
werden außerhalb der Funktionen ("global") vereinbart
und bekommen das Attribut "static"; die Funktionen
bekommen es aber nicht.
Alle Funktionen sind jetzt von außerhalb sichtbar,
nicht aber die Variablen.

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,

soweit verstanden, diese Setter und Getter bzw Wrapper nutze ich schon 
lange "intuitiv" im Interface eines Moduls. Vor allem damit Änderungen 
nicht überall gemacht werden müssen. Sie werden vom GCC ja ohnehin 
spurlos aufgelöst, bewirken halt nur die Kapselung.

Denke, dass das Thema damit schon geklärt ist. Danke, Leute!

: Bearbeitet durch User
Autor: Irgend W. (Firma: egal) (irgendwer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk B. schrieb:
> ...(4k auf Mikrocontroller ist blöd)...

Was ist denn daran "blöd" auf eine µC der 256k RAM hat?

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Irgend W. schrieb:
> Was ist denn daran "blöd" auf eine µC der 256k RAM hat?

Ähm.. hust... genauer gesagt sind es 8MB. 8MB SRAM am ExtMemory
Bus, da es ein kastriertes Disco Board ist, wo das Display runter
ist und durch ein serielles ILI9341 SPI Display ersetzt wurde.
Linker File entsprechend angepasst.

Er meint vielleicht, dass man 4k nicht unbedingt call-by value
übergeben sollte, weil das den Stack massiv aufbläst und
sinnlose Kopie-Rechenzeit verbrät.

: Bearbeitet durch User
Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk B. schrieb:

> structs kann man auch by-value übergeben. (4k auf Mikrocontroller ist
> blöd)

Auch am PC wird man hier normalerweise lieber Zeiger auf const 
übergeben.

Autor: A. S. (achs)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Getter und Setter sind oft sinnvoll. Wenn Du am Ende aber für jedes 
Datenfeld 2 oder mehr Funktionen hast, ist das Quatsch. Getter und 
Setter sind umso sinnvoller, je komplizierter der Zugriff ist (z.b. 
baudrate in Teiler umrechnen) oder je eher die Implementierung sich 
ändern kann (uint8 -> uint16 -> Zeiger ...).

Ein reines Feld fester Register ist oft als globale Struktur(en) genauso 
gut und bei vielen Bausteinen üblich.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ok, C++... Klassen und gekapselte Daten aber
> das kann ich leider nicht, ging bisher ohne auch.

Du musst ja nicht auf C++24 und kryptographischen Quelltext gehen, 
sondern dich erstmal auf "C-with-classes" beschränken.

Aus der C-Sicht ist eine Klasse erstmal nichts weiter als eine normale 
Struktur mit zusätzlichen Funktionen. Jedes Element (Variable oder 
Funktion) kann für externen Zugriff blockiert (private) oder freigegeben 
(public) werden.

Fertig. Das allein sollte dir weiterhelfen.
Und wenn Wilhelm loslegt, hörst du erstmal weg. :-)

Autor: Nick M. (muellernick)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
> Ok, C++... Klassen und gekapselte Daten aber
> das kann ich leider nicht, ging bisher ohne auch.

Jetzt zitier ich das auch noch. :-)
Es geht um Kapselung. Deine Datenstruktur geht den Rest des Programms so 
wenig wie möglich an.
Daher wandert deine globale Struktur in eine eigene .c und wird dort als 
static deklariert.
Im .h stehen nur die typedefs, enums, function, ... die nach aussen hin 
nötig sind.
Dann hast u (wie mehrfach genannt) getter und setter Funktionen die auf 
die Daten zugreifen können.
Alle Sicherheitsüberprüfungen (index out of range etc.) hast du somit 
nur in dem einen neuen .c. Der Rest des Programms kann sich darauf 
verlassen, dass möglichst jeder Unsinn abgefangen wird. Und auch in der 
Debug-Konsole ausgegeben wird.
Du kannst/sollst da auch die streaming-Funktion (senden an PC) 
reinbauen.

Alle Funktionen so weit möglich mit const Parametern, dann kann der 
Compiler die meisten selbst auferlegten Beschränkungen rausoptimieren.
Meistens kommt bei dem "data hiding" dabei sogar ein kompakterer Code 
raus. Einfach weil der Code in nur einem Modul auftaucht und nicht 
überall verteilt Kopien.


Nick

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S. R. schrieb:
> Du musst ja nicht auf C++24 und kryptographischen Quelltext gehen,
> sondern dich erstmal auf "C-with-classes" beschränken.

Reicht das das Studium einer Arduino Lib erstmal? Oder gleich das 
geballte 500 Seiten Werk "C++ für Dummies"? Ich habe schon vor zig 
Jahren um die Jahrtausendwende beim Bjarne Stroustrup abgeschaltet und 
nichts verstanden. Und lieber meine Original Ausgabe von K&R 
geschmökert.

: Bearbeitet durch User
Autor: Nick M. (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich habe schon vor zig
> Jahren um die Jahrtausendwende beim Bjarne Stroustrup abgeschaltet

Der Stroustrup ist ganz gut. Zumindest kann man sich da das Konzept der 
OOP erarbeiten. Auch als C-Programmierer!
Beim OOP gehts nur um das Konzept und das dann sinngemäß umzusetzen 
(wenn sinnvoll).
Und nicht vergessen, C++ hat als Präprozessor für C angefangen.

> und nichts verstanden. Und lieber meine Original Ausgabe von K&R
> geschmökert.

K&R find ich absolut fürchterlich. C in a nutshell von Koenig bei 
O'Reilly ist zum Nachschlagen und Auffrischen sehr gut. Nehme ich immer 
wieder gerne her.

Nick

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S. R. schrieb:
> Christian J. schrieb:
>> Ok, C++... Klassen und gekapselte Daten aber
>> das kann ich leider nicht, ging bisher ohne auch.
>
> Du musst ja nicht auf C++24 und kryptographischen Quelltext gehen,
> sondern dich erstmal auf "C-with-classes" beschränken.
>
> Aus der C-Sicht ist eine Klasse erstmal nichts weiter als eine normale
> Struktur mit zusätzlichen Funktionen. Jedes Element (Variable oder
> Funktion) kann für externen Zugriff blockiert (private) oder freigegeben
> (public) werden.
>
> Fertig. Das allein sollte dir weiterhelfen.
> Und wenn Wilhelm loslegt, hörst du erstmal weg. :-)

Ok, ich halte mich zurück ;-)

Aber: C++24 fällt durchs Raster ... C++23 wird spannend genug!

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
>> Du musst ja nicht auf C++24 und kryptographischen Quelltext gehen,
>> sondern dich erstmal auf "C-with-classes" beschränken.
>
> Reicht das das Studium einer Arduino Lib erstmal? Oder gleich
> das geballte 500 Seiten Werk "C++ für Dummies"? Ich habe schon
> vor zig Jahren um die Jahrtausendwende beim Bjarne Stroustrup
> abgeschaltet und nichts verstanden.

Um in deinen kleinen C-Code eine oder zwei Klassen einzubauen, um von 
einer globalen Monsterstruktur wegzukommen, braucht man weder das eine 
noch das andere.

Aber wenn du dich partout weigerst, auch nur den kleinsten Schritt in 
diese Richtung zu gehen, dann ist das Thema ohnehin tot.

> Und lieber meine Original Ausgabe von K&R geschmökert.

Wer nicht will, der hat schon.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Moin,
>
> auch mein Hobby Code soll sauber sein. Bei einem größeren Projekt mit
> einer Wetterstation für den F429, die auch noch 3 externe Sensoren
> bedient und ein extra Anzeige Display gibt es bei mir eine größere
> globale Struktur, in der etliche Wetter-Werte liegen, viele davon auch
> noch als Arrays of struct, da 5 Tage stundenweise gespeichert werden.
> Deswegen, damit das Ganze mit __packed in einem Rutsch per Funk an einen
> PC übertragen werden kann. Der Trümmer ist rund 4k gross, global
> external im main.h deklariert und in main.c implementiert, liegt per
> Linker Direktive im residenten Batt-gepufferten BKRAM drin, nahezu alle
> Routinen greifen darauf zu aus den ca 9 .c Files. Die einen füllen ihn,
> andere holen sich für die LCD Grafik alles da raus.

Hört sich nach FORTRAn an: alles in einem common-block.

> Ok, C++... Klassen und gekapselte Daten aber das kann ich leider nicht,

Warum KANNST du das nicht? Du kannst doch auch 16-Bit in ein uint16_t 
packen ...

Autor: Egon D. (egon_d)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
S. R. schrieb:

> Um in deinen kleinen C-Code eine oder zwei Klassen
> einzubauen, um von einer globalen Monsterstruktur
> wegzukommen, braucht man weder das eine noch das
> andere.

Mal eine Frage: Woher kommt eigentlich der
ununterdrückbare Drang auf µC.net, einem Fragesteller
eine deutlich kompliziertere Lösung zu empfehlen, als
er braucht?

Soweit ich das beurteilen kann, hat sein Problem mit
Kapselung zu tun. Kapseln kann man aber auch in
ANSI-C; dazu braucht's kein C++.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Egon D. schrieb:
> Soweit ich das beurteilen kann, hat sein Problem mit
> Kapselung zu tun. Kapseln kann man aber auch in
> ANSI-C; dazu braucht's kein C++.

Ich finde die Grundlagen von Klassen jetzt nicht besonders kompliziert. 
Insbesondere dann nicht, wenn es sich auf dem Niveau von "class als 
struct mit Funktionen" drin bewegt. Nix Mehrfachvererbung, Templates, 
Lambdas, STL, zukünftige Coolness oder so.

Aber ja, man kann auch in C ordentlich kapseln und auch komplette OOP 
mit (Einfach-)Vererbung hochziehen. Ich habe nie das Gegenteil 
behauptet.

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, es ging nur um das hier... schon 2 Jahre her. Kann man sicher 
eleganter machen.
struct maxima_t {
          /* --- Board Sensoren --- */
    float P_Max,
          P_Min,
          T_Innen_Max,
          T_Innen_Min,
          /* -- Funk Sensor -- */
          T_Ext_Max,
          T_Ext_Min,
          F_Ext_Max,
          F_Ext_Min;
};

typedef struct
{
    int32_t  id;                                         // = 0x1234 nach Initialisierung
    uint16_t ptr;
    float    P_Now,                                      // Aktueller Druckwert
             T_Now;                                      // Aktueller Innen-Temperaturwert

    uint32_t P_MaxGraph,                                 // Aktuell oberer Druckwert im Bargraphen
             P_MinGraph;

    float    T_MaxGraph,                                 // Schwankungen um den Messpunkt
             T_MinGraph;

    // Maxima der Historie: Innen-Temperatur, Druck
    float    T_MaxInHistory,                             // Maximaler gemessener INNEN Temperaturwert
             T_MinInHistory,                             // Minimaler gemessener INNEN Temperaturwert
             T_AvgInHistory;

    uint32_t P_MaxInHistory,                             // Maximaler gemessener Druckwert
             P_MinInHistory;                             // Minimaler gemessener Druckwert
    float    P_AvgInHistory;

    float    RegrSteigung;                               // Steigung der Regressionsgeraden
    float    Ext_Temperature;
    float    Ext_Feuchte;
    float    Ext_UBatt;
    gebiet_t gebiet;                                     // Hoch, Tief, Neutral
    uint8_t  ZFN;                                        // Zambretti Forecast Letter
    struct   data_t History[HISTORY_MAX_IDX+1];          // Historie, stuendliche Eintragungen

}  Work_t __attribute__ ((packed));


// __attribute__ ((packed))

// Flags für die Zeit
typedef struct {
   _Bool   rtc_1s,
           rtc_sec10,
           rtc_1min,
           rtc_1hr,
           rtc_120min,
           rtc_1day,
           tag_nacht_wechsel,
           night,
           rf_timeout,          // 1 = RF Modul meldete sich nicht mehr
           f_SendHistoryToDisplay,
           NRF24L01_IsPresent,
           backlight;

} flags_t;

: Bearbeitet durch User
Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel schrieb:
> Du kannst in der main getter und setter implentieren und die Struktur in
> der main.c definieren.

Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.
Brauche ich dann 1000 Getter+Setter oder wie habe ich mir das 
vorzustellen?

Autor: Nop (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Peter D. schrieb:

> Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.

Sowas solltest Du gar nicht erst haben.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Daniel schrieb:
>> Du kannst in der main getter und setter implentieren und die Struktur in
>> der main.c definieren.
>
> Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.

Was meinst Du mit Parametern bei einem struct?

> Brauche ich dann 1000 Getter+Setter oder wie habe ich mir das
> vorzustellen?

Wenn Du vorher eclipse benutzt hast, bestimmt noch mehr ;-)

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Peter D. schrieb:
>
> Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.
>
> Sowas solltest Du gar nicht erst haben.

Naja, MySQL auf uc ist vermutlich etwas heftig.

Autor: Peter D. (peda)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Nop schrieb:
> Sowas solltest Du gar nicht erst haben.

D.h. ich soll keine Steuerungen mehr bauen?
Die Physiker wollen bei Teilchenquellen und Analysatoren nen Haufen 
Spannungen/Ströme setzen, lesen, überwachen und regeln können. 100 
Parameter ist da eher eine kleine Anzahl.

Autor: Nick M. (muellernick)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
> Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.

Dann ist das vermutlich ein enum als Parameter und es gibt eine getter 
und eine setter-Funktion.

Nick

Autor: Peter D. (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Anbei mal die Struct.

Nick M. schrieb:
> Dann ist das vermutlich ein enum als Parameter und es gibt eine getter
> und eine setter-Funktion.

Enum ja, aber alle können direkt zugreifen.

: Bearbeitet durch User
Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Egon D. schrieb:
> Zugriff auf die Daten konsequent NUR über Getter und Setter, NIEMALS
> direkt auf die Variablen.

Peter D. schrieb:
> Angenommen ich habe eine Struct von 100 Parametern mit 5 Elementen.
> Brauche ich dann 1000 Getter+Setter oder wie habe ich mir das
> vorzustellen?

Auch wenn es in einigen Anfänger-C++-Lehrbüchern so diktiert wird: Für
jede Membervariable grundsätzlich und ohne nachzudenken eine Set- und
Get-Funktion zu schreiben, ist Unfug. Wäre das so gewollt, gäbe es in
C++ weder Structs noch Public-Variablen.

Dieser Meinung ist übrigens auch die C++-Prominenz:

  https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rh-get

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Nop schrieb:
>> Sowas solltest Du gar nicht erst haben.
>
> D.h. ich soll keine Steuerungen mehr bauen?

Du sollst Steuerungen nicht mit einem Megastruct bauen.

Autor: Nick M. (muellernick)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Peter D. schrieb:
> Enum ja, aber alle können direkt zugreifen.

Worauf? Auf die Daten? Das wäre nicht gewünscht. Der enum sagt, auf 
welches Datum mit dem getter/setter zugeriffen wird. Abhängig vom Typen.


Nick

Autor: Egon D. (egon_d)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:

> Egon D. schrieb:
>> Zugriff auf die Daten konsequent NUR über Getter und
>> Setter, NIEMALS direkt auf die Variablen.
>
> Peter D. schrieb:
>> Angenommen ich habe eine Struct von 100 Parametern mit
>> 5 Elementen. Brauche ich dann 1000 Getter+Setter oder
>> wie habe ich mir das vorzustellen?
>
> Auch wenn [...]

Quotemarder. Pfui!

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Egon D. schrieb:
> Quotemarder. Pfui!

Wieso Quotemarder?

Habe ich deine Aussage in irgendeiner Form sinnentstellend zitiert?

Wenn ja, musst du mir erklären, was du damit gemeint hast. Für mich ist
ihr Inhalt – nicht zuletzt durch die Hervorhebung der Wörter "NUR" und
"NIEMALS" – völlig unmissverständlich, unabhängig vom Kontext.

Autor: Egon D. (egon_d)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:

> Egon D. schrieb:
>> Quotemarder. Pfui!
>
> Wieso Quotemarder?
>
> Habe ich deine Aussage in irgendeiner Form
> sinnentstellend zitiert?

Durchaus, ja. :)


> Wenn ja, musst du mir erklären, was du damit gemeint hast.

Meine Aussage war:
"Wenn man eine Variable kapselt, muss man sie konsequent
kapseln. Das bedeutet, man greift NUR über die Methoden
und NIEMALS direkt auf die Variable zu -- und das geht
sogar auch in einer nicht-OOP-Sprache."

Du argumentierst aber gegen:
"Wann man kapselt, muss man IMMER ALLE Variablen kapseln."

Letzteres ist jedoch überhaupt nicht meine Aussage.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Egon D. schrieb:
> Meine Aussage war:
> "Wenn man eine Variable kapselt, muss man sie konsequent
> kapseln. Das bedeutet, man greift NUR über die Methoden
> und NIEMALS direkt auf die Variable zu -- und das geht
> sogar auch in einer nicht-OOP-Sprache."

Das hört sich vernünftig an, und das Ganze war wohl ein Missverständnis.
Ich habe deine Teilaussagen ursprünglich so verstanden:

Egon D. schrieb:
> Unabhängig von der Sprache - Kapseln:

"Man sollte immer Kapseln, auch in nicht OO-Sprachen."

> Zugriff auf die Daten konsequent NUR über Getter und Setter, NIEMALS
> direkt auf die Variablen.

"Da immer gekapselt wird, darf der Zugriff auf (Member-)Variablen nur
über Getter und Setter erfolgen."

Nachdem das Missverständnis nun aufgelöst ist, gehe ich davon aus, wir
beider der Meinung sind, dass Peda für seine 500 Struct-Elemente keine
Get- und Set-Funktionen braucht, oder?

Autor: Egon D. (egon_d)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:

> Ich habe deine Teilaussagen ursprünglich so verstanden:
>
> Egon D. schrieb:
>> Unabhängig von der Sprache - Kapseln:
>
> "Man sollte immer Kapseln, auch in nicht OO-Sprachen."

Verstehe. -- Nein, die Langform ist eher ungefähr so:

"Ich bin nicht qualifiziert, Dir einen Rat zu C oder C++
zu geben, aber Dein konkretes Problem lässt sich durch
sinnvolle Kapselung lösen, und Kapselung ist weitgehend
unabhängig von der konkreten Sprache anwendbar. Die
Regeln dafür sind folgende:..."


> Nachdem das Missverständnis nun aufgelöst ist, gehe ich
> davon aus, wir beider der Meinung sind, dass Peda für
> seine 500 Struct-Elemente keine Get- und Set-Funktionen
> braucht, oder?

Ja natürlich -- zumindest nicht für jedes Element einzeln :)

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wann immer Getter und Setter trivial sind, sind sie auf Überflüssigkeit 
zu prüfen. Leider bestehen viele Tools darauf, erstmal sämtliche dieser 
Funktionen zu erzeugen und weil Dogmatik zählt, macht die auch keiner 
weg.

Aber hey, in Kotlin wird jedes getX/setX-Pärchen als "virtuelle 
Membervariable" X betrachtet. Dann sieht es im Code wieder so aus, als 
ob man Membervariablen zuweist. Im Bytecode ist es natürlich trotzdem 
ein Funktionsaufruf.

Eine Struktur mit 100 Elementen als Klasse zu machen fällt übrigens 
meistens unter "Gottobjekt" und ist nach Dogma ebenfalls zu vermeiden. 
Aber manchmal braucht man sowas trotzdem.

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok.... ich lass euch dann mal weiter diskutieren. Meine Frage ist 
eigentlich beantwortet. Danke! Bin dann mal raus hier...

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ok.... ich lass euch dann mal weiter diskutieren. Meine Frage ist
> eigentlich beantwortet. Danke! Bin dann mal raus hier...

Was ist denn Dein Fazit?

Autor: Peter D. (peda)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Christian J. schrieb:
> Meine Frage ist
> eigentlich beantwortet. Danke! Bin dann mal raus hier...

Solche Antworten fallen unter die Rubrik, hätte man besser sein lassen 
sollen.
Wem willst Du damit helfen?

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Was ist denn Dein Fazit?

Dass man das so kapseln kann wie direkt oben beschrieben. Oder eben C++ 
verwenden. Zumindest werde ich es bei größeren Sachen machen, nicht aber 
wenn ich wie gerade nur 2 Module habe und es läuft und nie erweitert 
werden wird.
Mein "Game of Life" hat auch zwei Felder, wäre aber sinnlos die zu 
kapseln.  Ein Zugriff feld.alt[x][y] und feld.neu[x][y] bleibt immer so, 
zudem er bidirektional erfolgt. Da ändert auch ein Getter/Setter nichts 
dran.

: Bearbeitet durch User
Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Mein "Game of Life" hat auch zwei Felder, wäre aber sinnlos die zu
> kapseln.

Du könntest mehr Performance hinkriegen, wenn Du die kapselst und dann 
nur indirekt über Pointer an die Berechnungsfunktion gibst. Dann kannst 
Du Dir nämlich das Umkopieren von feld.neu nach feld.alt am Anfang eines 
Berechnungszyklus sparen.

Autor: Christian J. (Firma: privat) (christianj)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:

> Du könntest mehr Performance hinkriegen, wenn Du die kapselst und dann
> nur indirekt über Pointer an die Berechnungsfunktion gibst.

In dem Fall allerdings eher nicht. 1 Feld Lesen, "umkreisen" und 2.tes 
Feld erzeugen für die Grafik-Funktion, die das Feld abbildet.

Autor: Mw E. (Firma: fritzler-avr.de) (fritzler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Nop schrieb:
>> Sowas solltest Du gar nicht erst haben.
>
> D.h. ich soll keine Steuerungen mehr bauen?
> Die Physiker wollen bei Teilchenquellen und Analysatoren nen Haufen
> Spannungen/Ströme setzen, lesen, überwachen und regeln können. 100
> Parameter ist da eher eine kleine Anzahl.

Er meinte glaube, dass du kein einzelnes struct mit 100+ Members haben 
sollst.
zB kannste den Stromteil in ein struct packen, dass dan in dem großen 
struct wohnt.
Dann kannste dieses "substruct" der Funktion für die Stromeinstellung 
geben anstatt ALLES vom struct zu übergeben.

mbedTLS hat das so, da gibts structs in structs in structs in structs in 
structs usw.
Oben haste das große struct in der Hand für die eine TLS Verbindung, 
dann gibts in diesem ein struct für zB das Zertifikat, dann noch eins 
für das Schküsselpaar und eiens für die Sockets. Das Zertifikatstruct 
hat dann wieder memberstructs für die certchain etc.

Das sieht aber trotzdem gruselig aus:
https://tls.mbed.org/api/structmbedtls__ssl__context.html

Autor: Michael B. (laberkopp)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Egon D. schrieb:
> Mal eine Frage: Woher kommt eigentlich der
> ununterdrückbare Drang auf µC.net, einem Fragesteller
> eine deutlich kompliziertere Lösung zu empfehlen, als
> er braucht?
>
> Soweit ich das beurteilen kann, hat sein Problem mit
> Kapselung zu tun. Kapseln kann man aber auch in
> ANSI-C; dazu braucht's kein C++.

Weil irgendwann mal Irgendjemand was von angeblichen Vorzügen bestimmter 
Programmierweisen gelesen (oder in der Vorlesung gehört) hat, sei es 
Wiederverwendbarkeit oder eben Kapselung, und seit dem das ständig für 
Besser unter allen Umständen hält, er betet es wie ein Mantra runter 
ohne jemals selbst nachgedacht zu haben.

Das wirkt halt wie Werbung, Gehirn ausschalten.

Leider leiden unter solchen Leuten diejenigen, die wirklich die 
Hntergründe verstehen wollen und es richtig machen wollen.

Eine globale Variable erfordert nämlich zunächst mal einen Zugriff
LD reg,(address)
ist die Variable auf dem Stack muss der Stackframe addiert werden
LD pointerreg,address
ADD pointerreg,SP
LD reg,(pointerreg)
und hat man es malloct geht der Zugriff per Offset über eine pointer
LD pointerreg,address
ADD pointerreg,fieldoffset
LD reg,(pointerreg)
kommt ein getter/setter auf ein self hinzu muss ein call sein
PUSH self
CALL getter
  POP pointerreg (meist noch komplizierter compiliert)
  ADD pointerreg,fieldoffset
  LD returnreg,(pointerreg)
  RET
LD reg,returnreg ; vielleicht dasselbe
es sei denn der Compiler inlint den Aufruf.

Weil die meisten gar nicht wissen, welchen Overhead ihre 
Fehlentscheidungen so bewirken, sind heute alle Programme, auch bei 1000 
mal leistungsfähigerer Hardware, meistens lahmarschiger als noch vor 30 
Jahren, und natürlich 100 mal grösser.

JEDE Programmierweise, die (zur vollständigen Bearbeitung der Aufgabe 
inkl Fehlerbehandlung) auch nur 1 Befehl mehr auszuführenden code 
bewirkt, ist letztlich ein Programmierfehler.

Aber wenn es um die Worte geht, mit denen diese Programmierer ihre 
Fehler verteidigen, dann haben sie plötzlich tausend mal mehr Worte und 
Elan dafür, als für ein richtiges Programm.

Autor: Vincent H. (vinci)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommt da auch noch was konstruktives? Weil wenn das Mantra "da beste 
Assembler is kein Assembler" ist, dann kann der Threadersteller seinen 
F429 kübeln und sich an Wetterfrosch zulegen...

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael B. schrieb:

> JEDE Programmierweise, die (zur vollständigen Bearbeitung der Aufgabe
> inkl Fehlerbehandlung) auch nur 1 Befehl mehr auszuführenden code
> bewirkt, ist letztlich ein Programmierfehler.

Performance ist halt nicht die einzig relevante Metrik. In dem Maße, wie 
die Software komplexer wird, braucht man auch Methoden, diese 
Komplexität zu strukturieren, weil das sonst unwartbar wird.

Insbesondere, wenn sich wegen der normalen Job-Fluktuation auch noch 
jemand außer dem ursprünglichen Entwickler in überschaubarem Zeitrahmen 
in die Codebasis einarbeiten soll. Ebenso, wenn mehrere Entwickler am 
selben Projekt arbeiten, das tun sie dann gegen definierte 
Schnittstellen.

Unabhängig von der Programmiersprache sind Kapselung und Schichten ein 
probates Mittel, weil sie eine bestimmte Aufgabe in einem recht 
abgeschlossenen Bereich erledigen, der nach außen durch seine 
Schnittstellen interagiert. Will man da was ändern, muß man sich erstmal 
eben nur in diesen Bereich reinarbeiten.

Autor: Christian J. (Firma: privat) (christianj)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Michael B. schrieb:
> JEDE Programmierweise, die (zur vollständigen Bearbeitung der Aufgabe
> inkl Fehlerbehandlung) auch nur 1 Befehl mehr auszuführenden code
> bewirkt, ist letztlich ein Programmierfehler.

Das ist nun echt Quark. Heute geht es mehr darum dass der Mensch den 
Code noch versteht und strukturieren kann als dass die Maschine den 
Idealcode zu sehen kriegt.  Kannst ja versuchen eine optische KI in 
Assembler zu programmieren. Die Dinger sind so schnell, dass da ein paar 
Zeilen mehr nicht auffallen. Und Getter und Setter werden vom Compiler 
vollständig aufgelöst, die existieren gar nicht mehr!

: Bearbeitet durch User

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.

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