Forum: Mikrocontroller und Digitale Elektronik Programmierstil


von Fragender (Gast)


Lesenswert?

Ich wollte mal kurze Frage zum Design des Codens stellen.
Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.
Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt 
werden, wenn sie sich auch wirklich geändert haben.
Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe 
ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich 
ist.
Was ist der gängige Programmierstil?

von Bernd K. (prof7bit)


Lesenswert?

Fragender schrieb:
> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe
> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich
> ist.

Das kommt darauf an. Wie heißt die Funktion, was gibt sie vor zu tun, 
wie ist sie dokumentiert, was würde der Leser spontan erwarten wenn er 
das sieht, wie verhalten sich ähnliche Funktionen in anderen Teilen 
deines Codes, ist es naheliegend es so zu tun, wird es einfacher lesbar, 
führt es insgesamt zu weniger code?

von Oliver S. (oliverso)


Lesenswert?

Fragender schrieb:
> Was ist der gängige Programmierstil?

Egal, in welcher Progarmmiersprache, die Antwort auf solche Fragen ist 
immer 42.

Oliver

von Walter K. (vril1959)


Lesenswert?

Fragender schrieb:
> ....
> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.
> Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt
> werden, wenn sie sich auch wirklich geändert haben.
> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe
> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich
> ist.
> Was ist der gängige Programmierstil?

Mit anderen Worten: Du willst die function aufrufen und dann in der 
function prüfen ob sie was machen soll?

Ruf die function dann auf, wenn Du sicher bist dass Du sie brauchst!

von ausserdem (Gast)


Lesenswert?

Sorry, ich bin kein fernsehgucker. Musste erst Wikipedia fragen, was 42 
bedeutet. Kryptisches mit Kryptischem erklären? Hilft das?

von Volle (Gast)


Lesenswert?

wenn nur bei Änderung  gesendet wird macht das Initialisierungen und 
Diagnosen schwer.
i.d.R  gibt es dann eine mindeste und einen maximale Updaterate.




Was es immer geben sollte ist ein  aussagekräftiger Betreff

von Bernd K. (prof7bit)


Lesenswert?

Wenn es Dir irgendwie falsch vorkommt dann ist es wahrscheinlich falsch. 
Oder falsch dokumentiert. Oder falsch benannt. Scheib es so hin daß es 
offensichtlich wird und sich richtig anfühlt.

von Sebastian R. (sebastian_r569)


Lesenswert?

Wenn die Funktion in etwa "writeData()" heißt, würde ich als 
Außenstehender erwarten, dass die Daten immer geschrieben werden, sobald 
ich die Funktion aufrufe. "updateData()" oder "writeNewData()" klingen 
für mich eher so, dass nur geänderte Daten geschrieben werden.

Je, nachdem, wie oft welcher Fall benötigt wird (alle Daten schreiben 
oder nur Neue) könnte man der writeData() eine Wrapper-Funktion 
schreiben, die dann eben writeData() nur aufruft, wenn neue Daten da 
sind. Was natürlich wieder Sprünge und Zeit braucht.

Insgesamt ist es nicht festgelegt, wie man es umsetzt. Es sollte nur für 
andere ersichtlich sein, was eine Funktion tut.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Fragender schrieb:

> Was ist der gängige Programmierstil?

Je nach Komplexität kannst Du da auch 3 Funktionen draus machen:
- Eine die Sendet
- Eine die Daten vergleicht
- und eine, die Daten vergleicht und Kopie / Hash der Daten erstellt und 
sendet.

von HyperMario (Gast)


Lesenswert?

Fragender schrieb:
> Was ist der gängige Programmierstil?

Als Gelegenheitsprogrammierer hat das imo mit Stil wenig zu tun sondern 
mit Funktion.

Meiner einer bildet in der Software die Funktion ab (soweit möglich).

Wenn das "nichtsenden" zum senden gehört (z.B. zum Stromsparen) mache 
ich es da, gehört es zu den Daten (Gegenseite erwartet nur geänderte 
Daten) prüfe ich da.

Man kann natürlich auch eine extra Funktion schreiben und danach bedingt 
aufrufen. Das würde ich machen wenn es wichtig wäre und auffallen soll.

von Maik S. (Gast)


Lesenswert?

Ja,

Je nach verwendeter Struktur (ist es ein µC oder eine PC-Anwendung oder 
die Steuerung eines Flugzeuges) gibt es halt mehrere Kriterien an Hand 
derer du deine Auswahl treffen kannst.

Wenn das schreiben (oder Daten speichern...) zB innerhalb einer 
Interrupt Routine läuft, macht es Sinn das kontrollieren außerhalb und 
als eigene Funktion zu beschreiben.

etc. [beliebeige Beispiele]

In den meisten Anwendungen würde ich in der Konfiguration einen Flag 
setzen um diese Optimierung ein/ausschalten zu können (Testen / 
Fehlersuche) und bei Aktivierung das letzte gesendete Datenpaket immer 
im Speicher mit dem neuen Vergleichen vor jedem senden.

von Dirk K. (merciless)


Lesenswert?

ausserdem schrieb:
> Sorry, ich bin kein fernsehgucker. Musste erst Wikipedia fragen, was 42
> bedeutet. Kryptisches mit Kryptischem erklären? Hilft das?
Zur 42: https://de.wikipedia.org/wiki/Per_Anhalter_durch_die_Galaxis

Was dir der Schreiber damit sagen wollte: Ohne
ein paar Code-Schnipsel ist es sehr schwer, darauf
eine Antwort zu geben. Warum schreibst du den
Code nicht so hin, wie du denkst und fragst uns
dann hier um unsere Meinung? Wäre einfacher.

merciless

von G4st (Gast)


Lesenswert?

Ich denke du suchst sowas in der Art:
1
/* Hold the data that was sent the last time to check if it has been sent before */
2
uint8 myLocalData[128];
3
4
/* Function that sends data only if it differs from data sent in the previous call */
5
bool sendDataOnChange(uint8* data, uint16 length)
6
{
7
    bool returnValue = false;
8
9
    /* First check for valid input data before processing input data */
10
    if (data != NULL && length > 0)
11
    {
12
        /* Check that our buffer is not compromized */
13
        if(&myLocalData[0] != NULL)
14
        {
15
            /* Perform compare of the data sent the last time with the data requested to send */
16
            bool compare = memcmp( (void*)data, (void*)&myLocalData[0], length);
17
18
            if (0 != compare)
19
            {
20
                 /* In case the data differs, copy the requested data into our local buffer and sent the data */
21
                 memcpy((void*)&myLocalData[0],(void*)data,length);
22
                 returnValue = sendData((void*)&myLocalData[0], length);
23
            }
24
            else
25
            {
26
                /* Data already sent */
27
                returnValue = true;
28
            }
29
        }
30
    }
31
    else
32
    {
33
        /* Invalid data passed to the function */
34
        returnValue = false;
35
    }
36
37
    return returnValue;
38
}
39
40
bool sendData(uint8* data, uint16 length)
41
{
42
    if (data != NULL && length > 0)
43
    {
44
        /* Send data to a lower software module which performs the actual sending of data. */
45
    }
46
    [...]
47
}

BTW: Wenn du eine Frage so hineinwirfst, kommen ganz viele Trolle und 
machen dir den Thread kaputt. Wenn das Beispiel dir hilft, liegt es 
daran, dass ich deine Frage richtig interpretiert habe und nicht weil du 
sie gut beschrieben hast.

Ach und wenn jemand mit "Kommt drauf an" antwortet, brauchst du gar 
nicht erst weiterlesen. Diese Leute erwarten eine vollständige 
Spezifikation bevor sie sich herablassen eine Antwort zu geben. Wenn man 
allerdings alles im Detail spezifizieren kann, braucht man eine Antwort 
in der Regel auch nicht mehr. Solche Leute werden dann als erstes von 
Softwareentwicklern aus Low-Cost Ländern ersetzt. In meinen Augen dann 
auch kein Verlust.

Ein guter Ingenieur hat soviel Erfahrung, dass er vor allem fehlerhaft 
oder lückenhafte Spezifikationen von sich aus füllen/berichtigen kann 
und dann sein Lösungsvorschlag mit dem Auftraggeber zusammen gegen seine 
Erwartungen evalutiert.

Mit den Worten zum Donnerstag
   ein G4st

PS: Kannst du kurz Feedback geben ob dir das Beispiel geholfen hat?

von PittyJ (Gast)


Lesenswert?

ausserdem schrieb:
> Sorry, ich bin kein fernsehgucker. Musste erst Wikipedia fragen, was 42
> bedeutet. Kryptisches mit Kryptischem erklären? Hilft das?

Jeder weiss, was 42 bedeutet. Das gehört zum Grundwissen und wird 
typischerweise von den Eltern vermittelt. Es sei denn, die kommen aus 
Bielefeld.

von Purzel H. (hacky)


Lesenswert?

42 - die Antwort auf die Frage der Fragen : Was ist der Sinn von Allem.
Siehe : "Hitchhiker guide through the galaxis", oder so
Stellt die ultimaive Antwort auf fast alle Fragen dar.

Die Frage der Fragen wurde dann anders gestellt. Die Frager im Buch 
haben dann die Erde gebaut und der Prozess zur Beantwortung laeuft immer 
noch.

Beitrag #5762258 wurde von einem Moderator gelöscht.
von M. K. (sylaina)


Lesenswert?

G4st schrieb:
> Ach und wenn jemand mit "Kommt drauf an" antwortet, brauchst du gar
> nicht erst weiterlesen. Diese Leute erwarten eine vollständige
> Spezifikation bevor sie sich herablassen eine Antwort zu geben. Wenn man
> allerdings alles im Detail spezifizieren kann, braucht man eine Antwort
> in der Regel auch nicht mehr.

Wenn ich jetzt frage, was ich für mein Auto tanken muss, ist, denke ich, 
die Aussage durchaus berechtigt, dass es auf mein Auto ankommt, dass ich 
habe. Die Randbedingungen zum Problem zu benennen ist niemals falsch und 
ja, oft ergibt sich die Lösung aus den Randbedingungen ganz von alleine. 
Der Spruch, dass es hilfreich sei, mal einen Schritt zurück zu machen 
und das ganze Bild zu betrachten, kommt nicht von ungefähr ;)

von DPA (Gast)


Lesenswert?

Also ich verstehe das so:
 1) Es gibt Daten
 2) Daten werden geändert
 3) ???
 4) Geänderte Daten werden gesendet

Wichtig wäre nun, wann und wohin werden die Daten gesendet? Fragt jemand 
nach Änderungen? Oder ist jemand dauerhaft verbunden, und in 
regelmässigen Abständen werden die Daten gesendet?

Die Struktur und das Format der Daten ist auch wichtig. Und je nach 
Programmiersprache sind unterschiedliche Pattern einfacher umzusetzen.

Zunächst muss herausgefunden werden, ob die Daten geändert wurden. Dann 
ist noch die Frage, ob man das erste mal alle Daten braucht, oder ob man 
bestimmte Daten Subscriben kann und man nur die dann braucht, oder ob 
man die am Anfang manuell holt, etc.

Was sicher nötig ist, wäre eine Datenstruktur, z.B. eine Liste, aller 
Objekte, dessen Änderungen gesendet werden sollen. Bei einem subscriber 
Modell kann man das pro subscriber machen. Wenn alle alle beobachten 
kann man das auch global machen. Oder wenn es sonstige Kriterien je nach 
client gibt, kann man das zusammen mit den Infos über den Clienten 
speichern.
Je nach Anwendungsfall können auch andere Strukturen sinn machen. z.B. 
Bäume bei verschachtelten GUI Elementen, etc.

Ich denke das Erkennen geänderter Daten gibt es 6 wichtige Varianten, 
die mir spontan in den Sinn kommen:
 1) Es gibt einen callback, der bei jeder Änderung sofort ausgeführt 
wird. Man hat dann z.B. immer einen Setter dafür. Oder man verwendet 
Transaktionen.
 2) Dein Objekt mit den Daten, oder ein wrapper Objekt, hat ein flag, ob 
es geändert wurde. Von zeit zu zeit geht man alle einmal durch, sendet 
es an alle, und resettet das flag.
 3) Jedes Objekt hat ein Hash. Der Client sendet alle seine Hashs, und 
der Server sendet alle Objekte, wo dieser nicht mehr übereinstimmt. Kann 
je nachdem etwas ineffizient sein, dafür wird so geprüft, dass 
tatsächlich eine Änderung vorliegt, und man muss keine sonstigen state 
Informationen synchron halten. Das ist super für Caches geeignet, und 
wird so bei HTTP E-Tags gemacht. Aber achtung, es kann zu hash 
collisions kommen.
 4) Jedes Objekt hat einen Änderungstimestamp + einen counter. Bei jeder 
Änderung wird ein globaler counter erhöht, und der counter des Objekts 
darauf gesetzt, falls der Timestamp unverändert ist. Andernfalls wird 
der Timestamp des Objekts gesetzt, und der object counter sowie der 
globale counter auf 1 gesetzt. Der Client sendet nach dem 
Verbindungsaufbau den höchsten Timestamp + counter den er in seinen 
Objekten finden kann. Der server sendet dann alle Objekte, wo 
timestamp_client < timestamp_objekt || ( timestamp_client == 
timestamp_objekt && counter_client < counter_objekt ), sortiert so, dass 
das kleinste (timestamp, counter) paar zuerst kommt. Man könnte den 
Timestamp auch weglassen, und den server counter immer noch irgendwo 
persistieren.
 5) Bei änderungen wird das Objekt an das ende einer Sendequeue 
angehängt. Oder nur dessen serialisierte daten.
 6) Ne Kombination der anderen Optionen.

Was ich jetzt oben noch nicht behandle, ist das Löschen von Objekten.

Bei speziellen Formaten, wie z.B. Video Frames, muss man aber komplett 
anders vorgehen. Da kann man z.B. Bilder substrahieren, jpeg 
kommpressionsartige dinge machen, Translationsmatrizen berechnen, etc.

Und dann kann man das immer noch auf viele weisen Implementieren. Auf 
jeden Fall muss man die Daten vor dem Senden noch irgendwie 
serialisieren. Idealerweise abstrahiert man dass noch irgendwie. Bei 
JavaScript reicht häufig ein JSON.stringify, bzw. in PHP ein 
JSON_encode. In C++ gibt es Templatemagie. In C kann man z.B. den Typ 
als enum mit speichern, und dann ne lookup Tabelle für 
Serialisierungsfunktionen usw. machen. etc. Eventuell nimmt man dafür 
auch ein Framework.

Die Prüfung selbst macht man dann da, wo dies am einfachsten und 
möglichst einheitlich geht.

Noch was zum Schluss: Versuche immer zusammenhängende Daten 
(Verbindungsspezifische Daten eines Clienten, Daten einer Serverinstanz, 
etc.) in je eine Datenstruktur zu packen. Sowas in globalen Variablen 
unübersichtlich herumschwirren zu haben, kann schnell zum Albtraum 
werden.

von Axel S. (a-za-z0-9)


Lesenswert?

Fragender schrieb:
> Ich wollte mal kurze Frage zum Design des Codens stellen.

"Design des Codens" ... aua!

> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.

Ähm. Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird", 
nennt man üblicherweise Returnwert oder - wenn man zwanghaft 
eindeutscht - Rückgabewert. Und der Typ des Rückgabewerts ist fest. Er 
ist ein Teil der Funktions→Signatur, ebenso wie der Funktionsname.

> Jetzt möchte ich dazu programmieren, dass die Daten nur geschickt
> werden, wenn sie sich auch wirklich geändert haben.

Eine Funktion kann nicht "nichts" zurückgeben. Wenn der Rückgabewert 
z.B. vom Typ int ist, dann muß sie einen int zurückgeben. Was du 
aber machen kannst: du kannst einen bestimmten Wert, z.B. 0 dahingehend 
festlegen, daß er "nichts geändert" bedeutet.

> Mache ich die if-Bedingung dann direkt in die Funktion rein oder führe
> ich sie in diesem Fall nur bedingt aus, sodass die if klar ersichtlich
> ist.

Man kann eine Funktion nicht "bedingt ausführen". Wenn du außerhalb der 
Funktion feststellen kannst, daß sich nichts geändert hat, dann brauchst 
du die Funktion natürlich nicht aufzurufen. Aber dann ist deine ganze 
Frage sinnlos. Wenn wir hingegen mal annehmen, daß die Entscheidung, 
ob sich etwas geändert hat, nur innerhalb der Funktion getroffen 
werden kann, daß mußt du die Funktion in jedem Fall aufrufen. Und 
brauchst dann natürlich ein if(), um auszuwerten ob die Funktion 
vielleicht "es hat sich nichts geändert" zurück gegeben hat. Und 
innerhalb der Funktion ein weiteres if(), damit sie das tut.

Im Normalfall wird man diese Prüfung so früh wie möglich machen, damit 
man im Fall des Falles möglichst viel Code einsparen kann und die 
Sonderbedingung über möglichst wenige Aufrufebenen transportieren muß.

von svensson (Gast)


Lesenswert?

> Eine Funktion kann nicht "nichts" zurückgeben.
In C kann eine Funktion auch vom Typ "void" sein, dann gibt sie keine 
Daten zurück.

von Thomas E. (thomase)


Lesenswert?

Name H. schrieb:
> der Prozess zur Beantwortung laeuft immer
> noch.

Nein. Die Erde wurde fünf Minuten vor Ablauf von den Vogonen gesprengt, 
um einer Hyperraumumgehungsstraße Platz zu machen.

von Alex D. (daum)


Lesenswert?

Axel S. schrieb:
>> Da gibt es eine Funktion, die Daten schickt, wenn sie ausgeführt wird.
>
> Ähm. Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird",
> nennt man üblicherweise Returnwert oder - wenn man zwanghaft
> eindeutscht - Rückgabewert. Und der Typ des Rückgabewerts ist fest. Er
> ist ein Teil der Funktions→Signatur, ebenso wie der Funktionsname.

Ich denke eher, dass Fragender wirklich eine Funktion meint, die Daten 
irgendwo hinsendet. Da kann es durchaus sinnvoll sein, diese nur bei 
Änderung neu zu übertragen, wenn die Gegenstelle die Daten speichert.

von Axel S. (a-za-z0-9)


Lesenswert?

svensson schrieb:
>> Eine Funktion kann nicht "nichts" zurückgeben.
> In C kann eine Funktion auch vom Typ "void" sein, dann gibt sie keine
> Daten zurück.

Dann gibt sie niemals irgendwas zurück.
Und die Frage des TE erübrigt sich.


Alex D. schrieb:
> Axel S. schrieb:
>> Die "Daten die eine Funktion schickt, wenn sie ausgeführt wird",
>> nennt man üblicherweise Returnwert oder - wenn man zwanghaft
>> eindeutscht - Rückgabewert.
>
> Ich denke eher, dass Fragender wirklich eine Funktion meint, die Daten
> irgendwo hinsendet.

Oh. DU meinst im Sinne von: "eine Funktion, die eine Ein-/Ausgabeinheit 
(z.B. UART) bedient, um Daten zu verschicken". Hmm, ja. So kann man das 
auch interpretieren. Fand ich angesichts der Wortwahl des TE jetzt nicht 
naheliegend.

Aber auch dann gilt, was ich schrieb:
> Im Normalfall wird man diese Prüfung so früh wie möglich machen, damit
> man im Fall des Falles möglichst viel Code einsparen kann und die
> Sonderbedingung über möglichst wenige Aufrufebenen transportieren muß.

von Axel S. (a-za-z0-9)


Lesenswert?

Thomas E. schrieb:
> Die Erde wurde fünf Minuten vor Ablauf von den Vogonen gesprengt,
> um einer Hyperraumumgehungsstraße Platz zu machen.

<Trump> So sad! </Trump>

von svensson (Gast)


Lesenswert?

> Dann gibt sie niemals irgendwas zurück.
Muß sie ja auch nicht, da sie Daten versendet.

Dann ist es streng genommen keine Funktion mehr, sondern eine Prozedur.

von Thomas E. (thomase)


Lesenswert?

svensson schrieb:
> Dann ist es streng genommen keine Funktion mehr, sondern eine Prozedur.

In C gibt es keine Prozeduren.

von BabyYouCanDriveMyCar (Gast)


Lesenswert?

Axel S. schrieb:
> svensson schrieb:
>>> Eine Funktion kann nicht "nichts" zurückgeben.
>> In C kann eine Funktion auch vom Typ "void" sein, dann gibt sie keine
>> Daten zurück.
>
> Dann gibt sie niemals irgendwas zurück.


Meine Nachbarin ist dann auch eine Funktion. Die gibt auch nie wieder 
etwas zurück.

von Bernd K. (prof7bit)


Lesenswert?

BabyYouCanDriveMyCar schrieb:
>> Dann gibt sie niemals irgendwas zurück.
>
> Meine Nachbarin ist dann auch eine Funktion. Die gibt auch nie wieder
> etwas zurück.

Hat deine Nachbarin dann wenigstens Seiteneffekte? Hat sie irgendeine 
Wirkung auf Dich? Denn wenn nicht kannst Du sie ersatzlos wegoptimieren!

von Jella (Gast)


Lesenswert?

Schreib deine Daten in eine Variable und die lässt du dann vergleichen.
wenn sich eine änderung ergibt, rufst du deine gewünschte subroutine 
auf.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.