Forum: Compiler & IDEs Code unleserlich schreiben um Zeilen zu sparen.


von Mark W. (kram) Benutzerseite


Lesenswert?

Hallo,

schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
Oder geht das gar nicht?
1
if(output_mV < 100){o = 4; u = 5;}
2
            
3
if(output_mV > 99 && output_mV < 200){o = 6; u = 7;}
4
            
5
if(output_mV > 199 && output_mV < 300)
6
{
7
    o = 8;
8
    u = 9;
9
}
10
            
11
if(output_mV > 299 && output_mV < 400)
12
{
13
    o = 10;
14
    u = 11;
15
}
Ich bin gerade dabei fuer 30 ifs aus 150 Zeilen 30 zu machen.

von Markus F. (mfro)


Lesenswert?

Mark W. schrieb:
> Ich bin gerade dabei fuer 30 ifs aus 150 Zeilen 30 zu machen.

was genau spart man, wenn man Zeilen spart?

Hast Du eine überempfindliche Return-Taste?

von asdf (Gast)


Lesenswert?

Mark,

falls du bei mir als Software-Entwickler arbeiten würdest, würde ich 
dich allein für die Frage entlassen.

Du sparst keine Lesearbeit, du machst Arbeit. Warum denkt jeder 
Programmmierer er wäre eine special Snowflake und besser als der 
Compiler?

1. Schreib was du meinst
2. Verlass dich auf den Compiler
3. verwende in dem Projekt autoformat
4. das ganze soll geunit-tested werden

von Sven K. (quotschmacher)


Lesenswert?

Mark W. schrieb:
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
> Oder geht das gar nicht?

möchte ich zeilen sparen, schreibe ich gar keinen code...

von Peter D. (peda)


Lesenswert?

Mehrfache Bereichstests mache ich mit switch:
1
  switch( output_mV ){
2
    case   0 ...  99: o =  4; u =  5; break;
3
    case 100 ... 199: o =  6; u =  7; break;
4
    case 200 ... 299: o =  8; u =  9; break;
5
    case 300 ... 399: o = 10; u = 11; break;
6
    default:          o =  0; u =  0; break;
7
  }

: Bearbeitet durch User
von Cool (Gast)


Lesenswert?

Ich wusste nichtmal dass man mit Switch Bereiche testen kann

von Mark W. (kram) Benutzerseite


Lesenswert?

asdf schrieb:
> Mark,
>
> falls du bei mir als Software-Entwickler arbeiten würdest, würde ich
> dich allein für die Frage entlassen.
>
Ooops. Naja, zum Glueck bin ich ja kein Software-Entwickler.
War auch nicht so ernst gemeint, wollte nur mal sehen was die Fachleute 
dazu sagen.
Ging mir hier um die Uebersichtlichkeit, weil man da beim Schreiben 
weniger scrollen muss.

von Mark B. (markbrandis)


Lesenswert?

Cool schrieb:
> Ich wusste nichtmal dass man mit Switch Bereiche testen kann

Kann man auch regulär nicht, da dies nicht zum C-Standard gehört. 
Bestimmte Compiler wie der gcc unterstützen dies als eine Erweiterung.

: Bearbeitet durch User
von Ok (Gast)


Lesenswert?

Also kurzer unleserlicher Code soll besser sein als Leserlicher bei dem 
man länger scrollen muss...

von Mark W. (kram) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Mehrfache Bereichstests mache ich mit switch:
>
1
>   switch( output_mV ){
2
>     case   0 ...  99: o =  4; u =  5; break;
3
>     case 100 ... 199: o =  6; u =  7; break;
4
>     case 200 ... 299: o =  8; u =  9; break;
5
>     case 300 ... 399: o = 10; u = 11; break;
6
>     default:          o =  0; u =  0; break;
7
>   }
8
>

Oh, danke. Das Beispiel sehe ich mir die Tage nochmal an. Kommt gerade 
richtig. Ich habe mir switch auch schon dafuer ueberlegt.

von M.A. S. (mse2)


Lesenswert?

asdf schrieb:
> Du sparst keine Lesearbeit, du machst Arbeit. Warum denkt jeder
> Programmmierer er wäre eine special Snowflake und besser als der
> Compiler?
>
> 1. Schreib was du meinst
> 2. Verlass dich auf den Compiler
> 3. verwende in dem Projekt autoformat
> 4. das ganze soll geunit-tested werden
Fachlich eine sehr gute Antwort.


Aber das...
asdf schrieb:
> falls du bei mir als Software-Entwickler arbeiten würdest, würde ich
> dich allein für die Frage entlassen.
...ist ein ziemlich klingonischer Ansatz. Wenn Du über die Entlassung 
von Mitarbeiter zu entscheiden hättest und tatsächlich so entscheiden 
würdest (sprich: bei allen Fragen, Gedanken, Überlegungen der Kollegen, 
die Du spontan dumm findest), wärst Du sehr schnell eine One-Man-Show.

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Mark W. schrieb:
> asdf schrieb:
>> Mark,
>>
>> falls du bei mir als Software-Entwickler arbeiten würdest, würde ich
>> dich allein für die Frage entlassen.
>>
> Ooops. Naja, zum Glueck bin ich ja kein Software-Entwickler.
> War auch nicht so ernst gemeint, wollte nur mal sehen was die Fachleute
> dazu sagen.
> Ging mir hier um die Uebersichtlichkeit, weil man da beim Schreiben
> weniger scrollen muss.

Also nur getrolle. Moderatoren: Thread und User können weg.

von g457 (Gast)


Lesenswert?

> Ich wusste nichtmal dass man mit Switch Bereiche testen kann

Wie schon geschurbt wurde ist das non-standard. Würde hierzufirma wohl 
auch (berechtigterweise) zum Rauswurf führen.

von M.A. S. (mse2)


Lesenswert?

Hannes J. schrieb:
> Also nur getrolle. Moderatoren: Thread und User können weg.

von Mark B. (markbrandis)


Lesenswert?

Mark W. schrieb:
> Hallo,
>
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
> Oder geht das gar nicht?

Man kann alles machen - wenn man es sinnvoll begründen kann.

"Zeilen sparen" ist selten ein sinnvolles Argument. Für nicht 
verwendeten Speicherplatz bei den Sourcecode-Dateien gibt es kein Geld 
zurück. ;-)

von Mark W. (kram) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Mark W. schrieb:
>> Ich bin gerade dabei fuer 30 ifs aus 150 Zeilen 30 zu machen.
>
> was genau spart man, wenn man Zeilen spart?
>
Naja, ich finde es wird uebersichtlicher. Man hat mehr Code auf dem 
Bildschirm und da es sich immer um die gleich Funktionalitaet handelt, 
sieht man Fehler leichter, weil es eben symmetrischer ist.
Aber das ist ja relativ, verstehe schon, dass die Fachleute sich da an 
geltende Standards halten sollten, speziell wenn man im Team arbeitet.
Bei mir schaut da keiner hin, ist nur privat.

von Mark W. (kram) Benutzerseite


Lesenswert?

Ok schrieb:
> Also kurzer unleserlicher Code soll besser sein als Leserlicher bei dem
> man länger scrollen muss...

Hmm, wenn ich mir das genau ueberlege, wer sagt denn dass es unleserlich 
sein muss.
Wenn ich mein Beispiel nehme, dann wuerde ich das auch nach einem halben 
Jahr noch verstehen.

von Tom (Gast)


Lesenswert?

Übersichtlich wird es, wenn man solche Monster-Abfragen in eine Funktion 
wegräumt und die 150 Zeilen durch eine ersetzt:
1
calc_ou(output_mv, &o, &u);
Wenn in dieser Funktion, die nur eine Sache erledigt, 150 ähnliche 
Zeilen stehen, stört das keinen. Die Testbarkeit wurde schon erwähnt. 
Wenn man die Grenzen ständig anpasst, würde ich den Sourcecode dieser 
Funktion  generieren lassen, um Fehler zu vermeiden.

---------------------------------------
1
if(output_mV < 100 ......
2
if(output_mV > 99  ......
Die Grenzen so zu schreiben ist maximal verwirrend, weil für jede Grenze 
zwei verschiedene Zahlen da stehen. Bei der nächsten Anpassung ändert 
man die 100 und übersieht wahrscheinlich, dass die 99 auch hätte 
geändert werden müssen. Hätte man
1
if(output_mV < 100 .........
2
if(output_mV >= 100 ........
geschrieben, wäre das aufgefallen. Die verbreitete Aversion gegen <= und 
>= erschließt sich mir nicht.

---------------------------------------

Mark B. schrieb:
> "Zeilen sparen" ist selten ein sinnvolles Argument.
Wenn man eine Aversionen gegen die Benutzung von Funktionen hat, schon.

von militanter Zeilensparer (Gast)


Lesenswert?

1
if (output_mv >= 400) {
2
   u = o = 0;
3
} else {
4
   o = (output_mv / 100) * 2 + 2;
5
   u =o + 1.;
6
}

von Ivo -. (Gast)


Lesenswert?

Wenn ich nur so ganz kurze Anweisungen habe, schreibe ich auch mal ein 
if in eine Zeile, aber spätestens wenn ich mal den code beautifyer 
starte, habe ich eh wieder mehrer Zeilen.
Außerdem gibts ja auch Code-Folding, falls man möglichst viel auf einmal 
sehen muss.

Ivo

von Dr. Sommer (Gast)


Lesenswert?

Übersichtlich genug?
1
#include <iostream>
2
#include <stdexcept>
3
4
template <typename T>
5
void range (T value) {
6
  throw std::runtime_error ("Value out of range");
7
}
8
9
template <typename T, typename F, typename... Rest>
10
void range (T value, T border, F f, Rest&&... rest) {
11
  if (value < border)
12
    std::forward<F> (f) ();
13
  else
14
    range (value, std::forward<Rest> (rest)...);
15
}
16
17
int main() {
18
  try {
19
    int value = 85;
20
    range (value,
21
      50, [&] () { std::cout << "Keine 50\n"; },
22
      80, [&] () { std::cout << "Keine 80\n"; },
23
      90, [&] () { std::cout << "Keine 90\n"; }
24
    );
25
  } catch (const std::exception& e) {
26
    std::cerr << e.what () << std::endl;
27
  }
28
  
29
  return 0;
30
}

von Mark W. (kram) Benutzerseite


Lesenswert?

Tom schrieb:
>
1
> if(output_mV < 100 .........
2
> if(output_mV >= 100 ........
3
>
Gute Idee, werde ich mir mal angewoehnen. Ich hatte in der Tat einige 
Tippfehler bei den Bereichsueberlappungen.

von Tom (Gast)


Lesenswert?

Die zweifach hingeschriebenen Grenzen kann man sich auch mit sinnvoll 
plazierten elses sparen, wenn wie im Beispiel nur eine Zahl in 
Wertebereiche eingeordnet werden soll:
1
if (output_mV < 100){
2
    o =  4;
3
    u =  5;
4
}
5
else if (output_mV < 200) {
6
    o =  6;
7
    u =  7;
8
}
9
else if (output_mV < 300) {
10
    o =  8;
11
    u =  9;
12
}
13
else if (output_mV < 400) {
14
    o = 10;
15
    u = 11;
16
}

von Karl (Gast)


Lesenswert?

Oder man sucht ganz einfach in einer lut. Wenn man sowas öfter braucht, 
gibt es die Funktion dafür sowieso...

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Übersichtlich genug?

Nö, ich verstehe nur Bahnhof.

Rekursion mit variabler Argumentenliste, da kriegt man ja ne Knoten im 
Gehirn.

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Rekursion mit variabler Argumentenliste, da kriegt man ja ne Knoten im
> Gehirn.

Absolut gängige Praxis bei funktionaler Programmierung. So kann der 
Aufrufer mit wenig Code eine konsistente Bereichs-Abfrage bauen. Auf 
Wunsch fügt man noch eine Prüfung aufs Minimum hinzu.

von Mark W. (kram) Benutzerseite


Lesenswert?

Tom schrieb:
>
1
> if (output_mV < 100){
2
>     o =  4;
3
>     u =  5;
4
> }
5
> else if (output_mV < 200) {
6
>     o =  6;
7
>     u =  7;
8
> }
9
>
Das gefaellt mir sogar noch besser. Switch ist aber auch uebersichtlich.

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Absolut gängige Praxis bei funktionaler Programmierung.

Wenn ich das richtig sehe, ist die Abbruchbedingung der Rekursion das 
Fehlen weiterer Argumente.
Kann der Compiler sowas aufdröseln oder packt er wirklich zur Laufzeit 
den gesamten Wust an Argumenten auf den Stack?

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Wenn ich das richtig sehe, ist die Abbruchbedingung der Rekursion das
> Fehlen weiterer Argumente.
Richtig, aber die Bedingung wird beim Compilieren ausgewertet, nicht zur 
Laufzeit. Die Aufruftiefe ist also fix.

Peter D. schrieb:
> Kann der Compiler sowas aufdröseln oder packt er wirklich zur Laufzeit
> den gesamten Wust an Argumenten auf den Stack?
Nur wenn nicht geinlined wird. Wenn man sichergehen möchte dass alles 
geinlined wird schreibt man noch ein "__attribute__((always_inline)) 
inline" dran. Dann wird daraus praktisch eine simple if-else-Kette.

von Achim S. (Gast)


Lesenswert?

Was gefällt dir nicht an der Lösung, die schon weiter oben gepostet 
wurde?

militanter Zeilensparer schrieb:
>    o = (output_mv / 100) * 2 + 4;
>    u =o + 1;

(ich hab sie mal leicht abgeändert, weil vorher imho eine Zahl nicht 
exakt gestimmt hat)

Wenn deine 30 folgenden ifs alle so schön regelmäßig weiterzählen wie 
die ersten drei, dann lässt sich das doch alles zu dieser einfachen 
Formel zusammenfassen.

von Mark W. (kram) Benutzerseite


Lesenswert?

Achim S. schrieb:
> militanter Zeilensparer schrieb:
>>    o = (output_mv / 100) * 2 + 4;
>>    u =o + 1;
Habe ich gesehen. Habe nur noch nicht drauf geantwortet. Will ich morgen 
mal ausprobieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mark W. schrieb:
> Naja, ich finde es wird uebersichtlicher.

Kann, muss nicht.

Damit es übersichtlicher wird, müsste es wirklich alles auch schön
formatiert werden, dass es am Ende wie eine Tabelle aussieht.  In
solchen Fällen benutze ich sowas auch gelegentlich.

Der Gewinn an Lesbarkeit dadurch muss aber schon erheblich sein,
damit die Maßnahme gerechtfertigt ist.

ps: Das beißt sich dann natürlich mit der Überschrift, die du diesem
Thread gegeben hast. ;-)  Wenn es dadurch wirklich "unleserlich"
wird, ist es niemals gerechtfertigt.

asdf schrieb:
> 2. Verlass dich auf den Compiler

Dass man damit keinen Objektcode einspart, war wohl auch dem TE von
vornherein klar und in keiner Weise die Absicht.

Ivo Z. schrieb:
> spätestens wenn ich mal den code beautifyer starte

Einem solchen kann man normalerweise auch sagen, dass er bestimmte
Bereiche, die sorgsam manuell formatiert worden sind, nicht anfassen
soll.

: Bearbeitet durch Moderator
von tictactoe (Gast)


Lesenswert?

Mark W. schrieb:
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
> Oder geht das gar nicht?
> if(output_mV < 100){o = 4; u = 5;}

Habe ich früher mal gemacht. Dann hat man aber ein Problem, wenn man den 
Code schrittweise im Debugger durchgeht. Denn typischerweise springt der 
Debugger beim Single-Stepping über die ganze Zeile drüber, egal ob die 
Bedinung wahr oder falsch war. Um zu sehen, ob der Branch betreten 
worden ist oder wäre, muss man sich also vorher und nachher die 
Variablenwerte ansehen.

Schreibt man hingegen
1
if(output_mV < 100) {
2
  o = 4;
3
  u = 5;
4
}
dann sieht man beim Single-Stepping ganz klar, ob der Branch betreten 
wird oder nicht.

Deshalb schreibe ich schon lange keine kompakten if-Einzeiler mehr.

von Klaus (Gast)


Lesenswert?

tictactoe schrieb:
> Deshalb schreibe ich schon lange keine kompakten if-Einzeiler mehr.

ACK

MfG Klaus

von Rolf M. (rmagnus)


Lesenswert?

Mark B. schrieb:
> "Zeilen sparen" ist selten ein sinnvolles Argument. Für nicht
> verwendeten Speicherplatz bei den Sourcecode-Dateien gibt es kein Geld
> zurück. ;-)

"Zeilen sparen" kann aber ein sinnvolles Argument sein, wenn man dafür 
eine Funktion komplett auf den Bildschirm bekommt, statt viel scrollen 
zu müssen. Da muss man abwägen, was man nun besser lesbar findet: Alles 
schön sauber in einzelne Zeilen geschrieben, dafür so, dass man ständig 
scrollen muss, oder eher kompakt, dafür ist aber alles auf einen Blick 
zu sehen. Für mich muss Variante 1 nicht zwingend und unumstößlich das 
Optimum sein, auch wenn es hier Leute gibt, die das als Grund sehen 
würden, jemanden auf die Straße zu setzen…

Ich würde es dann sauber untereinander schreiben, passend zu einander 
eingerückt:
1
if (                   output_mV < 100) { o =  4; u =  5; }
2
if (output_mV >  99 && output_mV < 200) { o =  6; u =  7; }
3
if (output_mV > 199 && output_mV < 300) { o =  8; u =  9; }
4
if (output_mV > 299 && output_mV < 400) { o = 10; u = 11; }

So finde ich das besser lesbar und schneller erfassbar, als wenn da jede 
Klammer und jede Zuweisung ihre eigene Zeile bekommt. Und die 
angegebenen 30 Zeilen passen komplett auf den Bildschirm, die 150 eher 
nicht, was die Übersicht weiter verbessert.
Die vorher genannten Argumente, statt > 99 lieber >= 100 zu schreiben 
oder gleich else zu nutzen, um sich jeweils die Untergrenze zu sparen, 
sind auch sinnvoll.

Ivo Z. schrieb:
> Außerdem gibts ja auch Code-Folding, falls man möglichst viel auf einmal
> sehen muss.

Gerade das tut man bei Code-Folding ja nicht. Um zu erkennen, ob alle 
Zuweisungen an o und u richtig sind, muss ich erst sämtliche Folds 
öffnen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

tictactoe schrieb:
> dann sieht man beim Single-Stepping ganz klar, ob der Branch betreten
> wird oder nicht.

Bei üblicher brauchbarer Optimierung greift dieses Argument jedoch
so gut wie nicht.  Wirklich zeilenweises Abarbeiten funktioniert nur,
wenn man nicht optimiert.

von HildeK (Gast)


Lesenswert?

Rolf M. schrieb:
> Ich würde es dann sauber untereinander schreiben, passend zu einander
> eingerückt:
> if (                   output_mV < 100) { o =  4; u =  5; }
> if (output_mV >  99 && output_mV < 200) { o =  6; u =  7; }
> if (output_mV > 199 && output_mV < 300) { o =  8; u =  9; }
> if (output_mV > 299 && output_mV < 400) { o = 10; u = 11; }

Ich auch, aber die Reihenfolge umdrehen und was weglassen:
1
if (output_mV < 400) { o = 10; u = 11; }
2
if (output_mV < 300) { o =  8; u =  9; }
3
if (output_mV < 200) { o =  6; u =  7; }
4
if (output_mV < 100) { o =  4; u =  5; }
Ob die bei kleinen Werten erfolgende wiederholte Zuweisung günstiger ist 
als die Bereichsprüfung bei den größeren? Keine Ahnung, müsste man bei 
zeitkritischen Bedingungen mal überlegen bzw. anschauen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

HildeK schrieb:
> Ich auch, aber die Reihenfolge umdrehen und was weglassen
Ich würde noch was weglassen:
1
if (output_mV < 400) o = 10;
2
if (output_mV < 300) o =  8;
3
if (output_mV < 200) o =  6;
4
if (output_mV < 100) o =  4;
5
u = o+1;


Aber auch mir gefällt der Vorschlag mit dem direkten Berechnen am 
Besten.

von Programmiersprachentheaterintendant (Gast)


Lesenswert?

Solche "Zeilensparumstellungen" finde ich nur ok für die ersten paar 
Zeilen (in TE Bsp: keinesfalls alle 30 ifs) und zwar als Schuhlöffel um 
dem Gehirn bei der Mustererkennung auf die Sprünge zu helfen.
Letztlich muss solcher "tabellarisch datengesteuerter Code" nicht aus 30 
ifs bestehen sondern aus einer Schlaufe und einer (inlined?) Funktion 
welche sich durch die Wertetabelle arbeitet. Also wenn es sich nicht 
direkt berechnen lässt wie militanter Zeilensparer es zeigt.

30 ifs erfordern streng genommen (mindestens!) n*30 Testcases welche 
Niemand schreiben/pflegen/kontrollieren/protokollieren will. Für jede 
neue Übersetzung durch den Compiler!

Die Schlaufe + Funktion ist hingegen mit 1..2 Handvoll Testcases 
abgedeckt, ja sie kann sogar als binary wiederverwendet werden (lib zum 
linken) und muss nie wieder nachgetestet werden auch wenn die 
Parametertabelle andere Werte bekommt.

Dieser Gedankenablauf muss eigentlich schon stattfinden bevor 30 ifs 
auf je mehreren Zeilen darniedercodiert werden...  (ich hätte den Fleiß 
dazu schon gar nicht, ich kann ja Programmieren und nicht nur nach 
Diktat Code ergießen)

von Mark W. (kram) Benutzerseite


Lesenswert?

Achim S. schrieb:
> militanter Zeilensparer schrieb:
>>    o = (output_mv / 100) * 2 + 4;
>>    u =o + 1;
Fantastisch.
Ich habe es jetzt so gemacht und es funktioniert. Es brauch nicht einmal 
ein if Anweisung.
Gestern hatte ich ueberlegt und habe es nicht 100% verstanden wegen der 
Rundung. Aber da o und u int sind und alles nach dem Komma wegfaellt 
geht's wunderbar.
Auch alle anderen Vorschlaege haben meinen Horizont erweitert. :-)

: Bearbeitet durch User
von Karl (Gast)


Lesenswert?

militanter Zeilensparer schrieb:
> if (output_mv >= 400) {
>    u = o = 0;
> } else {
>    o = (output_mv / 100) * 2 + 2;
>    u =o + 1.;
> }

Militanter Deleygenerator.

Auf nem µC dauern die div 100 deutlich länger als die paar if-Abfragen.

von Karl ein anderer (Gast)


Lesenswert?

Karl schrieb:
> Auf nem µC dauern die div 100 deutlich länger als die paar if-Abfragen.
Kennst du nur AVR? Schon Cortex m3 haben ein div in Hardware.

Die direkte Berechnung hat aber einen viel wichtigeres

Karl schrieb:
> Oder man sucht ganz einfach in einer lut.
This.
Programmiersprachentheaterintendant schrieb:
> Letztlich muss solcher "tabellarisch datengesteuerter Code" nicht aus 30
> ifs bestehen sondern aus einer Schlaufe und einer (inlined?) Funktion
> welche sich durch die Wertetabelle arbeitet.
And this. Nur deutlich besser ausgedrückt.

Aber gut,  ich komme aus dem Automotive Bereich.  Da würde man 
gesteinigt für eine if Kaskade. Allein schon,  weil man die daten zur 
Laufzeit andern können muss.

von Stefan (Gast)


Lesenswert?

1
# if(output_mV > 99 && output_mV < 200){o = 6; u = 7;}
2
if output_mV in 100 ..< 200:
3
  o = 6
4
  u = 7

Für mich liest sich übermässig geschwätziger Code eher schlecht und 
erschwert das Verständnis.

von Wilhelm M. (wimalopaan)


Lesenswert?

Mark W. schrieb:
> Hallo,
>
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
> Oder geht das gar nicht?

Dein zu lösendes Problem besteht doch darin, in einer Menge von 
rechts-offenen Intervallen das Intervall zu finden, das einen bestimmten 
Wert beinhaltet. Und dieses Intervall möchtest Du durch einen Index 
kennzeichnen.

Die Frage ist, warum willst Du bei Deiner Lösung Zeilen sparen? 
Vermutlich, weil er unleserlich (geworden) ist.

Wann wird Code unleserlich? Wenn (zu) viel imperativ gemacht wird (wie 
bei Dir).
Deswegen gibt es ja auch die Empfehlungen:

a) benutze Algorithmen / Funktionen, keine expl. Iterationen
b) benutze Algorithmen / Funktionen, keine expl. Alternativen

Diese Empfehlungen führen zu deklarativem Code, und der ist in den Augen 
vieler besser lesbar, wartbar, testbar.
1
    constexpr auto limits = make_array(0, 50, 100, 200, 400, 800);
2
    constexpr auto intervals = make_intervals<RightOpen, Adjacent>(limits);
3
    
4
    int value = 100;
5
    
6
    auto index = lookup(value, intervals);

Man könnte sich auch folgendes vorstellen:
1
    auto index = Array(0, 50, 100) | Intervals<RightOpen, Adjacent>() | Lookup(value);

Code ist dann verständlich, wenn man explizit hinschreibt, WAS gemacht 
werden soll, aber nicht das WIE.
Natürlich muss man irgendwo einen Algorithmus schreiben, der die o.g. 
Intervalle konstruiert oder das Lookup durchführt. Dazu sind Iterationen 
und Alternativen notwendig. Wenn man die in seinem Anwendungscode nicht 
mehr haben will, gibt es nur die Möglichkeit, sie nach unten (oder 
manchmal auch nach oben) in der Abstraktionsschicht zu schieben.

von Stefan (Gast)


Lesenswert?

@Wilhelm M.

Ja das ist ganz nett, insbesondere da ich auch gerade mal wieder etwas 
C++ lerne...

Aber wie ist denn der daraus erzeugte Assembler code? Wirklich gleich 
gut optimiert als wie die ursprünglichen C Anweisungen? Bei uC ist das 
ja schon relevant, und sonnst eigentlich auch.

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan schrieb:
> @Wilhelm M.
>
> Ja das ist ganz nett, insbesondere da ich auch gerade mal wieder etwas
> C++ lerne...
>
> Aber wie ist denn der daraus erzeugte Assembler code? Wirklich gleich
> gut optimiert als wie die ursprünglichen C Anweisungen? Bei uC ist das
> ja schon relevant, und sonnst eigentlich auch.

Habe es nicht ausprobiert, aber ich gehe davon aus, dass der mindestens 
so gut wie die C Variante ist.

Das liegt daran, dass hier

1) die Intervalle constexpr sind, d.h. sie werden schon zur Compilezeit 
berechnet, und

2) Funktionstemplates ja immer inline-Kandidaten sind, denn ihre 
Definitions ist dem Compiler immer bekannt (template-header-only-libs 
haben immer diesen Vorteil), so dass die Inline-Heuristiken immer 
angewendet werden.

von Markus F. (mfro)


Lesenswert?

warum nicht einfach per Lookup-Table?

Dann kann man die Parameter auch noch zur Laufzeit ändern, falls 
notwendig.
1
int o, u;
2
3
struct output_mv_strc
4
{
5
    int fence;
6
    int out_o;
7
    int out_u;
8
} static output_mv_table[] =
9
{
10
    { 400, 10, 11 },
11
    { 300,  8,  9 },
12
    { 200,  6,  7 },
13
    { 100,  4,  5 },
14
    { 0 }
15
};
16
17
void set_output_mv(struct output_mv_strc table[], int output_mv)
18
{
19
    for (int i = 0; table[i].fence != 0; i++)
20
    {
21
        if (output_mv < table[i].fence)
22
        {
23
            o = table[i].out_o;
24
            u = table[i].out_u;
25
        }
26
    }
27
}

von Stefan (Gast)


Lesenswert?

Mark W. schrieb:
> Ich bin gerade dabei fuer 30 ifs aus 150 Zeilen 30 zu machen.

In diesem konkreten Fall kann man auch fünf daraus machen, etwa
1
let range = output_mV div 100
2
var o = range + 5
3
if range == 0:
4
  dec(o)
5
let u = o + 1

Zunächst den Bereich auf Integer-Werte abzubilden ist immer eine gute 
Idee, dann kann man die benötigten Zahlenwerte einfach in einem ARRAY 
ablegen.

von Stefan (Gast)


Lesenswert?

1
let range = output_mV div 100
2
var o = range + 5 - (range == 0).int
3
let u = o + 1

von Wilhelm M. (wimalopaan)


Lesenswert?

Markus F. schrieb:
> warum nicht einfach per Lookup-Table?

Das macht der Code, den ich gepostet hatte ja.

> Dann kann man die Parameter auch noch zur Laufzeit ändern, falls
> notwendig.
>
>
1
> int o, u;
2
> 
3
> struct output_mv_strc
4
> {
5
>     int fence;
6
>     int out_o;
7
>     int out_u;
8
> } static output_mv_table[] =
9
> {
10
>     { 400, 10, 11 },
11
>     { 300,  8,  9 },
12
>     { 200,  6,  7 },
13
>     { 100,  4,  5 },
14
>     { 0 }
15
> };
16
> 
17
> void set_output_mv(struct output_mv_strc table[], int output_mv)
18
> {
19
>     for (int i = 0; table[i].fence != 0; i++)
20
>     {
21
>         if (output_mv < table[i].fence)
22
>         {
23
>             o = table[i].out_o;
24
>             u = table[i].out_u;
25
>         }
26
>     }
27
> }
28
>

Mmh, da fallen mir gleich mehrere Sachen ein, warum das nicht gut ist:

1) der Sentinel (0) in der LUT zu verwenden ist sehr gefährlich
2) woraus kann man die Art des Intervalls (geschlossen, links-offen, 
rechts-offen) erkennen? Unklar.
3) globale Variablen (als return) (war hoffentlich ein Versehen)
4) in vielen Fällen ist der Datentyp int in der LUT nicht passend
5) der Typ der Iterationsvariable i als int ist auch ungünstig
6) der Code ist nicht allgemeingültig:
6a) der Name ist schlecht gewählt
6b) kann nur mit int's arbeiten

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan schrieb:
> Mark W. schrieb:
>> Ich bin gerade dabei fuer 30 ifs aus 150 Zeilen 30 zu machen.
>
> In diesem konkreten Fall kann man auch fünf daraus machen, etwa
>
>
1
> let range = output_mV div 100
2
> var o = range + 5
3
> if range == 0:
4
>   dec(o)
5
> let u = o + 1
6
>
>
> Zunächst den Bereich auf Integer-Werte abzubilden ist immer eine gute
> Idee, dann kann man die benötigten Zahlenwerte einfach in einem ARRAY
> ablegen.

Auch das halte ich für nicht gut:

1) das geht nur für reguläre, benachbarte Intervalle
2) auch hier ist die Art des Intervalls unklar bzw. im Code versteckt.
3) imperativer Code, der seine Bedeutung schlecht offenbart, weil in 
einzelnen Statements versteckt.
4) well, basic ...

von Wilhelm M. (wimalopaan)


Lesenswert?

In übrigen liefert
1
volatile uint8_t result;
2
volatile uint8_t value = 100;
3
4
int main() {
5
    
6
    if ((value >= 0) && (value < 10)) {
7
        result = 0;
8
    }    
9
    else if ((value >= 10) && (value < 20)) {
10
        result = 1;
11
    }
12
    else if ((value >= 20) && (value < 40)) {
13
        result = 2;
14
    }
15
    else if ((value >= 40) && (value < 80)) {
16
        result = 3;
17
    }
18
    else if ((value >= 80) && (value < 160)) {
19
        result = 4;
20
    }
21
}

z.B. auf AVR wesentlich größeren Code als:
1
volatile uint8_t result;
2
volatile uint8_t value = 100;
3
4
constexpr auto limits = std::make_array<uint8_t>(0, 10, 20, 40, 80, 160);
5
constexpr auto intervals = make_intervals<RightOpen, Adjacent>(limits);
6
7
int main() {
8
    auto index = lookup(value, intervals);
9
    if (index) {
10
        result = *index;
11
    }
12
}

von Stefan (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Auch das halte ich für nicht gut:

Nö gut nicht unbedingt, daher schrieb ich ja auch

>In diesem konkreten Fall kann man auch fünf daraus machen, etwa

Man sollte halt nur wissen dass man es machen kann. Wenn man sicher ist, 
dass das Schema diese konkrete Form beibehält, so ist es nicht unbedingt 
schlecht und liefert guten ausführbaren Code. Und der Fall, dass man aus 
einem Integer-Ausgangswert einfach Indizes 0, 1, 2, ... machen kann 
kommt nicht so selten vor, dann kann man damit leicht auf eine Tabelle 
in Form eines Arrays zugreifen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> if ((value >= 0) && (value < 10)) {
>         result = 0;

Da value ein uint8_t ist, trifft die Bedingung >= 0 immer zu.

In den folgenden Else-Zweigen ist der >= -Vergleich jeweils überflüssig, 
denn wenn die Bedingung nicht zutrifft, trifft der jeweils vorhergehende 
Vergleich zu.

Damit fällt
1
volatile uint8_t result;
2
volatile uint8_t value = 100;
3
4
int main() {
5
    
6
    if ((value >= 0) && (value < 10)) {
7
        result = 0;
8
    }    
9
    else if ((value >= 10) && (value < 20)) {
10
        result = 1;
11
    }
12
    else if ((value >= 20) && (value < 40)) {
13
        result = 2;
14
    }
15
    else if ((value >= 40) && (value < 80)) {
16
        result = 3;
17
    }
18
    else if ((value >= 80) && (value < 160)) {
19
        result = 4;
20
    }
21
}

zusammen zu
1
volatile uint8_t result;
2
volatile uint8_t value = 100;
3
4
int main() {
5
    
6
    if (value < 10) {
7
        result = 0;
8
    }    
9
    else if (value < 20) {
10
        result = 1;
11
    }
12
    else if (value < 40) {
13
        result = 2;
14
    }
15
    else if (value < 80) {
16
        result = 3;
17
    }
18
    else if (value < 160) {
19
        result = 4;
20
    }
21
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:

>
1
> volatile uint8_t result;
2
> volatile uint8_t value = 100;
3
> 
4
> int main() {
5
> 
6
>     if (value < 10) {
7
>         result = 0;
8
>     }
9
>     else if (value < 20) {
10
>         result = 1;
11
>     }
12
>     else if (value < 40) {
13
>         result = 2;
14
>     }
15
>     else if (value < 80) {
16
>         result = 3;
17
>     }
18
>     else if (value < 160) {
19
>         result = 4;
20
>     }
21
> }
22
>

Das sind dann immer zusammenhängende, also angrenzende Intervalle. Und 
das erste Intervall ist [-INT_MAX, 10[.

Ich bin mir nicht sicher, ob das beim TO immer gegeben ist. Und falls 
man von der impliziten Sortierung abweicht, wird es falsch.

von MaWin (Gast)


Lesenswert?

Man kann aus der einfachsten Sache eine Wissenschaft machen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Und das erste Intervall ist [-INT_MAX, 10[.

Nein. Welchen Datentyp hat "value"?

von Dr. Sommer (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Wilhelm M. schrieb:
> Und das erste Intervall ist [-INT_MAX, 10[.
>
> Nein. Welchen Datentyp hat "value"?

Selbst wenn es int wäre, wäre -INT_MAX nicht das Minimum... Außer auf 
Plattformen die das 1er-Komplement nutzen.

Beitrag #5442176 wurde von einem Moderator gelöscht.
Beitrag #5442296 wurde von einem Moderator gelöscht.
Beitrag #5442347 wurde von einem Moderator gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:
> Wilhelm M. schrieb:
>> Und das erste Intervall ist [-INT_MAX, 10[.
>
> Nein. Welchen Datentyp hat "value"?

Ja stimmt: ich hatte es vorher mit int geschrieben ...

Und natürlich wird der unnötige Vergleich vom Compiler wegoptimiert.

Der exemplarische C-Code war eher dazu gedacht, die Analogie zum 
generischen Code darzustellen.

Dr. Sommer schrieb:
> Rufus Τ. F. schrieb:
>> Wilhelm M. schrieb:
>> Und das erste Intervall ist [-INT_MAX, 10[.
>>
>> Nein. Welchen Datentyp hat "value"?
>
> Selbst wenn es int wäre, wäre -INT_MAX nicht das Minimum... Außer auf
> Plattformen die das 1er-Komplement nutzen.

Stimmt auch. Bezogen auf int natürlich [INT_MIN, 10[.

Und es gibt noch einen Unterschied: da die Parameterübergabe an die 
lookup<>() Funktion per-value erfolgt, wird das volatile nur einmal 
gelesen. Im C-Code erfolgt der Zugriff dementsprechend in jedem if-stmt. 
Wenn das nicht gewollt ist, dann sollte man in C auch eine Funktion 
schreiben und die Intervallgrenzen als Array übergeben (wurde oben schon 
mal gepostet mit dem Problem des sentinels) oder eben:
1
volatile uint8_t result;
2
volatile uint8_t v = 100;
3
4
int main() {
5
6
    // ...
7
8
    {
9
        uint8_t value = v;
10
        if ((value < 10)) {
11
            result = 0;
12
        }    
13
        else if ((value < 20)) {
14
            result = 1;
15
        }
16
        else if ((value < 40)) {
17
            result = 2;
18
        }
19
        else if ((value < 80)) {
20
            result = 3;
21
        }
22
        else if ((value < 160)) {
23
            result = 4;
24
        }
25
    }
26
27
    // ...
28
}

Beitrag #5442401 wurde von einem Moderator gelöscht.
von Jobst Q. (joquis)


Lesenswert?

militanter Zeilensparer schrieb:
> if (output_mv >= 400) {
>    u = o = 0;
> } else {
>    o = (output_mv / 100) * 2 + 2;
>    u =o + 1.;
> }

Du bist noch nicht militant genug:

u = o = 0;
if (output_mv < 400) {
     o = (output_mv / 100) * 2 + 2;
     u =o + 1;
     }

von Wilhelm M. (wimalopaan)


Lesenswert?

Jobst Q. schrieb:
> u = o = 0;
> if (output_mv < 400) {
>      o = (output_mv / 100) * 2 + 2;
>      u =o + 1;
>      }

Na dann;
1
u = o = 0;
2
if (output_mv < 400) u = (o = (output_mv / 100) * 2 + 2) + 1;

von Jobst Q. (joquis)


Lesenswert?

Wilhelm M. schrieb:
> if (output_mv < 400) u = (o = (output_mv / 100) * 2 + 2) + 1;

Stimmt. Die Aufgabe war ja nicht nur Zeilen zu sparen, sondern auch 
unleserlich zu schreiben.

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> z.B. auf AVR wesentlich größeren Code als:

Ist überhaupt kein Wunder, wenn Du ihm mit "volatile" die Fußfesseln 
anlegst. Er muß dann für jeden Vergleich und sei er noch so überflüssig, 
die Variable neu vom RAM einlesen. Optimieren ist da absolut verboten.
Schreib es als Funktion um, mit Argument und Returnwert.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Wilhelm M. schrieb:
>> z.B. auf AVR wesentlich größeren Code als:
>
> Ist überhaupt kein Wunder, wenn Du ihm mit "volatile" die Fußfesseln
> anlegst. Er muß dann für jeden Vergleich und sei er noch so überflüssig,
> die Variable neu vom RAM einlesen. Optimieren ist da absolut verboten.
> Schreib es als Funktion um, mit Argument und Returnwert.

Lies die vorherigen Beiträge: hatte ich oben schon beschrieben 
(allerdings eben nicht als Funktion in C, denn das hatte der TO auch 
nicht. Zu den Problemen der geposteten Funktion mit Array der 
Intervallgrenzen hatte ich auch schon etwas geschrieben).

von Erwin D. (Gast)


Lesenswert?

Mark W. schrieb:
> Ging mir hier um die Uebersichtlichkeit

Das passt aber nicht zu deiner eigenen Aufgabe:
Re: Code unleserlich schreiben um Zeilen zu sparen.

von Mark W. (kram) Benutzerseite


Lesenswert?

Erwin D. schrieb:
> Mark W. schrieb:
>> Ging mir hier um die Uebersichtlichkeit
>
> Das passt aber nicht zu deiner eigenen Aufgabe:
> Re: Code unleserlich schreiben um Zeilen zu sparen.
Ja, ich gebe zu die Ueberschrift war etwas falsch ausgedrueckt.
Statt "unleserlich" koennte ich auch "abweichend von der Norm" 
geschrieben haben. Das traefe es dann besser.
Aber der Post hat sich fuer mich gelohnt, ich habe viele verschiedene 
Sreibweisen fuer eine Aufgabe gesehen.
Danke nochmal an alle Beteiligten.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Code "kurz" und "unleserlich" schreiben muss nicht immer paarweise 
auftreten. Oftmals fällt eine Codepassage in sich zusammen, wenn man 
sich mal Gedanken macht, und wird gleichzeitig einfacher verständlich. 
Leider wird Code oftmals nur "hingerotzt"...

von A. S. (Gast)


Lesenswert?

Mark W. schrieb:
> Ja, ich gebe zu die Ueberschrift war etwas falsch ausgedrueckt.
> Statt "unleserlich" koennte ich auch "abweichend von der Norm"

Wollte ich auch gerade schreiben. Und ja, der Code wird (bei 
vorausgesetzter, geeigneter IDE) leserlicher, wenn das komplette if im 
Blocksatz in eine Zeile gequetscht wird. Nur dann kann man überhaupt mit 
dem Auge erkennen, ob
 - eine Systematik besteht
 - die Änderungen der Werte gleichen Mustern folgen
 - Schreibfehler dazwischen gerutscht sind (z.B. u und o bei einem if 
vertauscht)
 - welche (der hier vorgestellten) Optimierungen möglich/nötig/sinnvoll 
sind.

Da wir Code sowieso nur für uns (und nicht für den Compiler) schreiben, 
sollte eine Optimierung (zu einer Formel) auch nur erfolgen, wenn es 
dadurch noch besser lesbar wird! (Abgesehen von den ganz wenigen Fällen, 
in denen Speicher- oder Zeit-Optimierung notwendig ist)

von xxx (Gast)


Lesenswert?

g457 schrieb:
> Wie schon geschurbt wurde ist das non-standard. Würde hierzufirma wohl
> auch (berechtigterweise) zum Rauswurf führen.

Höhöhö, die rauswerfen dürfen, haben meistens nicht das notwendige 
Fachwissen.

Beitrag #5443762 wurde von einem Moderator gelöscht.
Beitrag #5443766 wurde von einem Moderator gelöscht.
von Jobst Q. (joquis)


Lesenswert?

Achim S. schrieb:
> Da wir Code sowieso nur für uns (und nicht für den Compiler) schreiben,
> sollte eine Optimierung (zu einer Formel) auch nur erfolgen, wenn es
> dadurch noch besser lesbar wird!

Wenn eine Systematik besteht, ist mir eine Formel allemal lieber als 
eine lange Reihe von 'if's oder 'case's. Nicht nur aus 
Optimierungsgründen, sondern auch von der Verständlichkeit her. Muss ich 
sonst ja erst alles durchlesen, um zu erkennen, ob die Systematik 
durchgehend ist.

Außerdem widerspricht es dem Prinzip "Don't repeat yourself", was sich 
auch auf die Wartbarkeit auswirkt.

Wenn die Werte keine Systematik haben, aber ein Raster (hier 100) würde 
ich ein Array nehmen und die Werte in die Deklaration schreiben.

o = arr[ output_mv /100];
u = o + 1;

von Wilhelm M. (wimalopaan)


Lesenswert?

Jobst Q. schrieb:

> Wenn die Werte keine Systematik haben, aber ein Raster (hier 100) würde
> ich ein Array nehmen und die Werte in die Deklaration schreiben.
>
> o = arr[ output_mv /100];
> u = o + 1;

Das ist doch genau der oben beschrieben LUT Ansatz: Du hast eine 
Wertemenge, die bestimmt die Anzahl der Einträge in der Tabelle, und Du 
eine Abbildung des Definitionsbereiches auf die Indizes der Tabelle.

Die spannende Frage ist, wie kommt man auf die Eingangsabbildung und wie 
füllt man die Tabelle, und welche Datentypen sind sinnvoll. Das macht 
der generische Code, den ich oben mal gepostet hatte.

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> volatile uint8_t result;
> volatile uint8_t value = 100;
>
> constexpr auto limits = std::make_array<uint8_t>(0, 10, 20, 40, 80,
> 160);
> constexpr auto intervals = make_intervals<RightOpen, Adjacent>(limits);
>
> int main() {
>     auto index = lookup(value, intervals);
>     if (index) {
>         result = *index;
>     }
> }

Ich krieg da nur Fehler:
1
test.cpp:6: error: expected constructor, destructor, or type conversion before 'auto'
2
test.cpp:7: error: expected constructor, destructor, or type conversion before 'auto'
3
test.cpp: In function 'int main()':
4
test.cpp:10: error: ISO C++ forbids declaration of 'index' with no type
5
test.cpp:10: error: 'intervals' was not declared in this scope
6
test.cpp:10: error: 'lookup' was not declared in this scope
7
test.cpp:12: error: invalid type argument of 'unary *'

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:

> Ich krieg da nur Fehler:
>
1
> test.cpp:6: error: expected constructor, destructor, or type conversion 
2
> before 'auto'
3
> test.cpp:7: error: expected constructor, destructor, or type conversion 
4
> before 'auto'
5
> test.cpp: In function 'int main()':
6
> test.cpp:10: error: ISO C++ forbids declaration of 'index' with no type
7
> test.cpp:10: error: 'intervals' was not declared in this scope
8
> test.cpp:10: error: 'lookup' was not declared in this scope
9
> test.cpp:12: error: invalid type argument of 'unary *'
10
>

Zeig doch mal Deinen ganzen Text (nicht nur einen Ausschnitt).

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Das Ergebnis von gcc -v wäre wohl eher interessant.
Wobei dem Quelltext wohl schon das ein- oder andere headerfile fehlt.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Das Ergebnis von gcc -v wäre wohl eher interessant.

ja, wobei heutzutage eher das Flag -std=...

> Wobei dem Quelltext wohl schon das ein- oder andere headerfile fehlt.

Worauf ich damit hinweisen wollte ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> constexpr auto limits = std::make_array<uint8_t>(0, 10, 20, 40, 80, 160);
> constexpr auto intervals = make_intervals<RightOpen, Adjacent>(limits);

Mir gefiele diese Lösung prinzipiell ganz gut, wenn ich wüsste, was ich
für make_intervals includen muss? Auch make_array ist nicht
Standard, aber immerhin in experimental/array bzw.im Namespace
std::experimental enthalten. make_intervals hingegen kann ich weder in
der (experimentellen) Standardbibliothek noch in den Boost-Bibliotheken
finden.

von Oliver S. (oliverso)


Lesenswert?

Wilhelm ist vermutlich mit einem pre-Alpha gcc 10 unterwegs, und nutzt 
C++27. PeDa kommt mit seinem erprobten 3er gcc, und alle anderen hängen 
irgendwo dazwischen.

Da kommt es schon mal zu Unverständlichkeiten ;)

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Mir gefiele diese Lösung prinzipiell ganz gut, wenn ich wüsste, was ich
> für make_intervals includen muss? Auch make_array ist nicht
> Standard, aber immerhin in experimental/array bzw.im Namespace
> std::experimental enthalten. make_intervals hingegen kann ich weder in
> der (experimentellen) Standardbibliothek noch in den Boost-Bibliotheken
> finden.

Oh, das hört sich jetzt so ein bisschen Arduino-like an: ich kann die 
lib nicht finden...

Oliver S. schrieb:
> Wilhelm ist vermutlich mit einem pre-Alpha gcc 10 unterwegs, und nutzt
> C++27.

Mmh, C++27 wird es wohl nicht geben.

>PeDa kommt mit seinem erprobten 3er gcc, und alle anderen hängen
> irgendwo dazwischen.
>
> Da kommt es schon mal zu Unverständlichkeiten ;)

Ok, dann versuche ich das mal aufzuklären. Ich poste einfach mal den 
ganzen Code. Allerdings auch dann wird es wohl nicht klappen, ihr 
braucht nämlich ein constexpr sort<>() (hier: Util::sort<>()), das 
std::sort<>() ist nicht constexpr. Das es zur Compilezeit verwendet 
wird, tut es ein Bubblesort ;-) (das zu schreiben überlasse ich gerade 
Euch).
1
#include <algorithm>
2
#include <array>
3
#include <experimental/array>
4
#include <utility>
5
#include <optional>
6
#include <util/algorithm.h> // Util::sort() 
7
#include <iostream>
8
9
struct RightOpen;
10
struct LeftOpen;
11
struct Closed;
12
struct Open;
13
14
struct Adjacent;
15
struct Disjoint;
16
17
template<typename T, typename Type>
18
struct Interval {
19
    typedef T value_type;
20
    typedef Type kind_type;
21
    constexpr bool includes(T v) const {
22
        if constexpr(std::is_same_v<Type, RightOpen>) {
23
            return (v >= left) && (v < right);
24
        }
25
        else {
26
            // ...
27
        }
28
    }
29
    T left{};
30
    T right{};
31
};
32
33
template<typename T, typename Type>
34
struct Boundary {
35
    typedef T value_type;
36
    constexpr bool includes(T v) const {
37
        if constexpr(std::is_same_v<Type, RightOpen>) {
38
            return (v < upper);
39
        }
40
        else {
41
            // ...
42
        }
43
    }
44
    T upper{};
45
};
46
47
template<typename Type, typename Construct, typename Limits>
48
constexpr auto make_intervals(const Limits& limits) {
49
    if constexpr(!std::is_same_v<Construct, Adjacent>) {
50
        using item_type = typename Limits::value_type;
51
        std::array<Interval<item_type, Type>, limits.size() - 1> in;
52
        for(typename Limits::size_type n = 0; n < in.size(); ++n) {
53
            in[n].left = limits[n];
54
            in[n].right = limits[n + 1];
55
        }
56
        return in;
57
    }
58
    else {
59
        auto sorted = limits;
60
        Util::sort(sorted);        
61
        using item_type = typename Limits::value_type;
62
        std::array<Boundary<item_type, Type>, limits.size()> in;
63
        for(typename Limits::size_type n = 0; n < in.size(); ++n) {
64
            in[n].upper = limits[n];
65
        }
66
        return in;
67
    }
68
}
69
70
template<typename T, typename Intervals, typename Function>
71
constexpr void lookup(const T& value, const Intervals& intervals, const Function& f) {
72
    for(typename Intervals::size_type n = 0; n < intervals.size(); ++n) {
73
        if (intervals[n].includes(value)) {
74
            f(n);
75
            break;
76
        }
77
    }
78
}
79
80
volatile int result = -1;
81
volatile int value = 5;
82
83
constexpr auto limits = std::experimental::make_array(0, 10, 20, 40, 80, 160);
84
//constexpr auto intervals = make_intervals<RightOpen, Adjacent>(limits);
85
constexpr auto intervals = make_intervals<RightOpen, Disjoint>(limits);
86
87
int main() {
88
    lookup(value, intervals, [](auto index){result = index;});
89
    
90
    std::cout << "Result: " << result << '\n';
91
}

Alles andere ist schnell heruntergetippt, ein paar Fälle habe ich auch 
ausgelassen, manche Namen sind nicht gut. Man könnte es schöner machen. 
Es soll ja nur das Prinzip zeigen...

Allerdings sollte man m.E. auch eine andere Variante realisieren, die 
nur mit elementar-konstanten Grenzen arbeitet. Denn diese hier kann ja 
auch mit non-constexpr arbeiten.

von Markus F. (mfro)


Lesenswert?

*Thema verfehlt!*

Die Aufgabe hiess, Code unleserlich schreiben, um Zeilen zu sparen!

Ernsthaft: es ist beeindruckend, was mit modernem C++ alles geht. Aber 
glaubst Du wirklich, dass das die µC-Programmierung - in Zeiten, wo der 
Durchschnittsprogrammierer kaum eine Arduino-loop() fehlerfrei hinkriegt 
- voranbringt?

von Wilhelm M. (wimalopaan)


Lesenswert?

Markus F. schrieb:
> *Thema verfehlt!*

Prinzip nicht verstanden!

> Die Aufgabe hiess, Code unleserlich schreiben, um Zeilen zu sparen!

Es sind im Code des Klienten (!) 3 Zeilen. Und das bei beliebig vielen 
Intervallen, die geschlossen/halboffen sein können und benachbart oder 
nicht, und auch noch für beliebige Datentypen.

> Ernsthaft: es ist beeindruckend, was mit modernem C++ alles geht. Aber
> glaubst Du wirklich, dass das die µC-Programmierung - in Zeiten, wo der
> Durchschnittsprogrammierer kaum eine Arduino-loop() fehlerfrei hinkriegt
> - voranbringt?

Ja, davon bin ich überzeugt.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Wilhelm M. schrieb:
> Markus F. schrieb:
>> Ernsthaft: es ist beeindruckend, was mit modernem C++ alles geht. Aber
>> glaubst Du wirklich, dass das die µC-Programmierung - in Zeiten, wo der
>> Durchschnittsprogrammierer kaum eine Arduino-loop() fehlerfrei hinkriegt
>> - voranbringt?
>
> Ja, davon bin ich überzeugt.

Vielleicht wäre es gut in den Beispielen die C++-Version und die 
Minimum-Compilerversion anzugeben. Im obigen Fall C++14/gcc4.9. Es gibt 
ja auch noch Leute, die Winavr2010(gcc4.3 oder so) benutzen, das 
behindert diese dann beim Mitüberzeigtsein.
Wobei gcc7.3 komplett C++17 kann, man also nicht wirklich Angst vor 
Alpha-Versionen haben muß, wenn man ganz up TO Date sein will,
z.B. mit "if constexpr"

von Oliver S. (oliverso)


Lesenswert?

Wilhelm M. schrieb:
> Mmh, C++27 wird es wohl nicht geben.

Das war schon so gemeint, wie es da steht. 20, 23, 26, dazu auf dem Weg 
dahin ein Jahr Verspätung, das passt schon.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>> Mir gefiele diese Lösung prinzipiell ganz gut, wenn ich wüsste, was ich
>> für make_intervals includen muss? Auch make_array ist nicht
>> Standard, aber immerhin in experimental/array bzw.im Namespace
>> std::experimental enthalten. make_intervals hingegen kann ich weder in
>> der (experimentellen) Standardbibliothek noch in den Boost-Bibliotheken
>> finden.
>
> Oh, das hört sich jetzt so ein bisschen Arduino-like an: ich kann die
> lib nicht finden...

Naja, ich dachte, ich hätte da vielleicht irgendein neues C++17- oder
C++20-Feature verpasst, was aber offensichtlich nicht der Fall ist, da
du make_intervals und lookup selber geschrieben hast.

Damit hat aber deine Lösung in meinen Augen ganz gewaltig an Eleganz
verloren. Natürlich kann man jedes noch so komplexe Problem mit einem
Ein- oder Zweizeiler lösen, wenn diese Zeilen aus Aufrufen von
Funktionen bestehen, die erst noch entwickelt werden müssen. Im
konkreten Fall hast du ein Problem, das man auf klassische Weise in 1
bis 10 Codezeilen (je nachdem, ob die Schwellwerte äquidistant sind oder
nicht) umsetzen würde, durch ein Konstrukt gelöst, das zugegebenermaßen
ganz pfiffig ist, dafür aber 70 Codezeilen umfasst und dabei noch nicht
einmal Dinge wie die Optimierungsmöglichkeit im Fall von äquidistanten
Schwellwerten nutzt.

Wenn man bedenkt, dass der zusätzliche Code auch getestet, gedebugt und
dokumentiert werden muss und dass man diese Intervallsuche nur relativ
selten benötigt, hat man mit deiner Lösung außer Erkenntnisgewinn nichts
gewonnen und stattdessen zusätzlichen Entwicklungsaufwand verursacht.

Ganz anders läge der Fall, wenn die Funktionen make_interval und
lookup durch die Standardbibliothek bereitgestellt würden. Dann würde
der Aufwand für Implementierung, Test, Debugging und Dokumentation
weitgehend entfallen, so dass die Lösung fast jeder selbstgeschriebenen
Variante vorzuziehen wäre.

Das ist auch der Grund, warum ich nachgefragt habe. Obwohl ich deine
negative Antwort eigentlich schon erwartet habe, bin ich jetzt doch ein
ganz klein wenig enttäuscht :)


PS:

Wilhelm, mal Hand aufs Herz: Glaubst du, der TE hätte es von sich aus
wirklich geschafft, nach dem Lesen deines Beitrags vom 02.06.2018
09:44 die Funktionen make_intervals und lookup selber zu schreiben?

Mark W. schrieb:
> Naja, zum Glueck bin ich ja kein Software-Entwickler.


PPS:

Wilhelm M. schrieb:
> a) benutze Algorithmen / Funktionen, keine expl. Iterationen

Wilhelm M. schrieb:
>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>         ...
>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>         ...
>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>         ...

Wilhelm M. schrieb:
> b) benutze Algorithmen / Funktionen, keine expl. Alternativen

Wilhelm M. schrieb:
>         if constexpr(std::is_same_v<Type, RightOpen>) {
>         ...
>         if constexpr(std::is_same_v<Type, RightOpen>) {
>         ...
>     if constexpr(!std::is_same_v<Construct, Adjacent>) {
>         ...
>         if (intervals[n].includes(value)) {
>         ...

: Bearbeitet durch Moderator
von Carl D. (jcw2)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> b) benutze Algorithmen / Funktionen, keine expl. Alternativen
>
> Wilhelm M. schrieb:
>>         if constexpr(std::is_same_v<Type, RightOpen>) {
>>         ...
>>         if constexpr(std::is_same_v<Type, RightOpen>) {
>>         ...
>>     if constexpr(!std::is_same_v<Construct, Adjacent>) {
>>         ...
>>         if (intervals[n].includes(value)) {
>>         ...

"if constexpr" ist nicht so leicht durch anderes ersetzbar (außer 
kompliziertem Template-Zeugs)


BTW, das hatte ich beim Überfliegen gar nicht bemerkt, also IST das 
C++-17.

von René H. (mumpel)


Lesenswert?

Mark W. schrieb:
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
> Oder geht das gar nicht?
> if(output_mV < 100){o = 4; u = 5;}

Ich mag soetwas garnicht. Bei mir (in VBA) bekommt jede Variable eine 
eigene Deklarationszeile und einen sprechenden Namen. Damit ich immer 
weiss welche Variable was macht.

von René H. (mumpel)


Lesenswert?

Mark W. schrieb:
> Ging mir hier um die Uebersichtlichkeit, weil man da beim Schreiben
> weniger scrollen muss.

Übersichtlichkeit erreicht man durch Einrücken. Oder durch Auslagern von 
Codeteilen in Rückgabefunktionen. Zumindest in VBA ist es einfach. Wenn 
ich eine umfangreiche Userform erstellen muss lagere ich die Prozeduren 
in Module aus. Jede Prozedur in ein eigenes Modul. Das Modul bekommt den 
Namen der Prozedur, wobei ein "mdl" davorgesetzt wird (Modul und 
Prozedur dürfen nicht den selben Namen tragen, sonst kommt es zu 
Konflikten). Die Callbacks im Userform-Codemodul rufen dann nur die 
Prozeduren auf und sind somit einzeilig. Ergebnis ist eine gute 
Übersichtlichkeit die ich auch noch nach Jahren problemlos 
nachvollziehen kann, und scrollen muss ich dann auch nicht mehr (es sei 
denn der Code ist etwas länger).

von A. S. (Gast)


Lesenswert?

René H. schrieb:
> Oder durch Auslagern von
> Codeteilen in Rückgabefunktionen

Das gilt nicht "absolut". Ganz grob, bei einem Anfänger-Projekt von 1000 
Zeilen sind ~10 Files je ~10 Funktionen je ~10 Zeilen vielleicht 
übersichtlich. Bei 1E5 Codezeilen würde man die 30 Zeilen des TO NICHT 
auslagern (wenn sie nur einmal gebraucht werden). Dann sind auch 
Funktionen mit 100 oder 1000 Zeilen normal und Tabellen (Blocksatz) ein 
Mittel der Wahl.

von Dr. Sommer (Gast)


Lesenswert?

Achim S. schrieb:
> Dann sind auch Funktionen mit 100 oder 1000 Zeilen normal und Tabellen
> (Blocksatz) ein Mittel der Wahl.

Das ist eher Spaghetti Code. Gerade bei großen Projekten sollten 
Funktionen nicht so lang werden. Besser ist es, viele kleine Funktionen 
(ca 10 Zeilen) zu haben, die genau einen Aspekt bearbeiten und alles 
andere ggf. delegieren. So werden sie viel leichter verständlich. Diese 
typischen Riesen-Algorithmen in Anfänger-Code lassen sich meist in viele 
kleine Einheiten aufteilen. Die kann man dann auch wieder verwenden.
Große Tabellen sollten auch eher die Ausnahme sein. Oft lassen die sich 
auch automatisch per constexpr generieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Carl D. schrieb:
> Wilhelm M. schrieb:
>> Markus F. schrieb:
>>> Ernsthaft: es ist beeindruckend, was mit modernem C++ alles geht. Aber
>>> glaubst Du wirklich, dass das die µC-Programmierung - in Zeiten, wo der
>>> Durchschnittsprogrammierer kaum eine Arduino-loop() fehlerfrei hinkriegt
>>> - voranbringt?
>>
>> Ja, davon bin ich überzeugt.
>
> Vielleicht wäre es gut in den Beispielen die C++-Version und die
> Minimum-Compilerversion anzugeben.

Ja, sicher: ab C++17, also -std=c++17 oder -std=c++2a

> Im obigen Fall C++14/gcc4.9. Es gibt
> ja auch noch Leute, die Winavr2010(gcc4.3 oder so) benutzen, das
> behindert diese dann beim Mitüberzeigtsein.

AVR wird eher schwierig, da es keine libstdc++ offiziell für die 
8-Bitter gibt. Ich habe meine eigene Realisierung, die bestimmte 
Optimierungen bzgl. der intern verwendeten DT macht.

> Wobei gcc7.3 komplett C++17 kann, man also nicht wirklich Angst vor
> Alpha-Versionen haben muß, wenn man ganz up TO Date sein will,
> z.B. mit "if constexpr"

Oh, seit 02.05.18 haben wir auch 8.1 released, der kann auch 
familiar-template-syntax für generische lambdas. Das finde ich sehr 
schön.

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Wilhelm M. schrieb:
>> Mmh, C++27 wird es wohl nicht geben.
>
> Das war schon so gemeint, wie es da steht. 20, 23, 26, dazu auf dem Weg
> dahin ein Jahr Verspätung, das passt schon.

Der Standard wird sich nicht verspäten, das wird C++26. Allerdings 
werden wohl einige Compiler wieder notorisch hinter hinken.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Yalu X. schrieb:
>>> Mir gefiele diese Lösung prinzipiell ganz gut, wenn ich wüsste, was ich
>>> für make_intervals includen muss? Auch make_array ist nicht
>>> Standard, aber immerhin in experimental/array bzw.im Namespace
>>> std::experimental enthalten. make_intervals hingegen kann ich weder in
>>> der (experimentellen) Standardbibliothek noch in den Boost-Bibliotheken
>>> finden.
>>
>> Oh, das hört sich jetzt so ein bisschen Arduino-like an: ich kann die
>> lib nicht finden...
>
> Naja, ich dachte, ich hätte da vielleicht irgendein neues C++17- oder
> C++20-Feature verpasst, was aber offensichtlich nicht der Fall ist, da
> du make_intervals und lookup selber geschrieben hast.
>
> Damit hat aber deine Lösung in meinen Augen ganz gewaltig an Eleganz
> verloren. Natürlich kann man jedes noch so komplexe Problem mit einem
> Ein- oder Zweizeiler lösen, wenn diese Zeilen aus Aufrufen von
> Funktionen bestehen, die erst noch entwickelt werden müssen.

Ja, das sollte man auch tun. Dann seine Testfälle dafür schreiben und 
diese Funktion in seinen Werkzeugkasten legen.

> Im
> konkreten Fall hast du ein Problem, das man auf klassische Weise in 1
> bis 10 Codezeilen (je nachdem, ob die Schwellwerte äquidistant sind oder
> nicht) umsetzen würde, durch ein Konstrukt gelöst, das zugegebenermaßen
> ganz pfiffig ist, dafür aber 70 Codezeilen umfasst

Dafür kann dieses Konstrukt eben auch mit allen Intervallarten und allen 
Datentypen umgehen. Das ist schon ein wesentlicher Unterschied.

> und dabei noch nicht
> einmal Dinge wie die Optimierungsmöglichkeit im Fall von äquidistanten
> Schwellwerten nutzt.

Aus das wäre kein Problem, statt Intervalle anzugeben, eine 
Abbildungsfunktion anzugeben. (BTW: wobei man bei der Indizierung eines 
rohen Arrays zumindest mal Assertionen über die Indizes einbauen sollte, 
und nicht wie es oben schon mal gepostet wurde.)

> Wenn man bedenkt, dass der zusätzliche Code auch getestet, gedebugt und
> dokumentiert werden muss

Das ist kein Argument, denn Dein Code muss auch getestet, korrigiert und 
dokumentiert werden. Allerdings mache ich das in meiner Bibliothek 
einmal und Du in jeder Anwendung immer wieder.

> und dass man diese Intervallsuche nur relativ
> selten benötigt, hat man mit deiner Lösung außer Erkenntnisgewinn nichts
> gewonnen und stattdessen zusätzlichen Entwicklungsaufwand verursacht.

Das ist eine Milchmädchenrechnung: um Copy-n-Paste Lösungen vorzubeugen, 
sollte man versuchen, so viel wie möglich zu generalisieren und aus 
Bibliotheken zu entnehmen bzw. eben den eigenen Bibliotheken 
hinzuzufügen. Der Aufwand hat sich im Gesamten schnell wieder 
amortisiert.

> Ganz anders läge der Fall, wenn die Funktionen make_interval und
> lookup durch die Standardbibliothek bereitgestellt würden. Dann würde
> der Aufwand für Implementierung, Test, Debugging und Dokumentation
> weitgehend entfallen, so dass die Lösung fast jeder selbstgeschriebenen
> Variante vorzuziehen wäre.

Ja, aber die libstdc++ ist nicht allumfassend und wird es auch nie sein. 
Vielleicht gibt es auf dieser Welt eine andere vertrauensvolle 
Bibliothek, die das realisiert - ich habe nicht danach gesucht.

Aber: schreibst Du keine Bibliotheken für Deine Projekte bzw. 
Anwendungsdomäne?

> Das ist auch der Grund, warum ich nachgefragt habe. Obwohl ich deine
> negative Antwort eigentlich schon erwartet habe, bin ich jetzt doch ein
> ganz klein wenig enttäuscht :)

Du bist enttäuscht, dass die libstdc++ dafür keine mundgerechte Lösung 
parat hat? Man könnte es mit adjacent_find<>() machen ... allerdings ist 
das nicht constexpr, was ja hier hilfreich wäre.

> PS:
>
> Wilhelm, mal Hand aufs Herz: Glaubst du, der TE hätte es von sich aus
> wirklich geschafft, nach dem Lesen deines Beitrags vom 02.06.2018
> 09:44 die Funktionen make_intervals und lookup selber zu schreiben?

Das kann und will ich nicht beurteilen. Aber es könnte sein, das der TE 
und einige andere etwas an Erkenntnis aus dieser Diskussion mitnimmt. 
Und sei es auch nur, neugierig auf Neues zu sein.

> PPS:
>
> Wilhelm M. schrieb:
>> a) benutze Algorithmen / Funktionen, keine expl. Iterationen
>
> Wilhelm M. schrieb:
>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>         ...
>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>         ...
>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>         ...

Dies bezieht sich immer auf den Code der Klienten. Wie meinst Du denn, 
ist z.B. ein std::copy<>() implementiert?

Es ist wichtig, die Grenze zwischen Code des Klienten und den 
Bibliotheken zu beachten. Im obigen Beispiel war es eigentlich klar. 
Also nochmal: das meiste ist bibliotheksbezogen, nur make_array, 
make_intervals und lookup ist für den Klienten.

> Wilhelm M. schrieb:
>> b) benutze Algorithmen / Funktionen, keine expl. Alternativen
>
> Wilhelm M. schrieb:
>>         if constexpr(std::is_same_v<Type, RightOpen>) {
>>         ...
>>         if constexpr(std::is_same_v<Type, RightOpen>) {
>>         ...
>>     if constexpr(!std::is_same_v<Construct, Adjacent>) {
>>         ...
>>         if (intervals[n].includes(value)) {
>>         ...

Auch hier gilt natürlich das oben Gesagte: auch ein std::find<>() wird 
nicht ohne eine Laufzeit-Alternative auskommen. Hier ist es allerdings 
kein Laufzeit-if, sondern eine bedingte template-Instanziierung (bis auf 
das letzte zitierte if).

von Carl D. (jcw2)


Lesenswert?

Wilhelm M. schrieb:
> Ja, sicher: ab C++17, also -std=c++17 oder -std=c++2a
>
>> Im obigen Fall C++14/gcc4.9. Es gibt
>> ja auch noch Leute, die Winavr2010(gcc4.3 oder so) benutzen, das
>> behindert diese dann beim Mitüberzeigtsein.
>
> AVR wird eher schwierig, da es keine libstdc++ offiziell für die
> 8-Bitter gibt. Ich habe meine eigene Realisierung, die bestimmte
> Optimierungen bzgl. der intern verwendeten DT macht.
Kenn ich ;-) Macht es schwierig die oft verlangten Beispiele zu liefern, 
ohne gleich ein dickes Zip-File dazupacken zu müssen. Ich hab mir bisher 
immer Dinge, die mir gefehlt haben, entweder aus dem Original geliehen, 
oder wenn's Triviales war, einfach selber geschrieben.

> Oh, seit 02.05.18 haben wir auch 8.1 released, der kann auch
> familiar-template-syntax für generische lambdas. Das finde ich sehr
> schön.
Dann wird's noch schwieriger, denn dann wollen/müssen die ja auch noch 
den "Selbstbau"-Compiler dazu haben.

von Wilhelm M. (wimalopaan)


Lesenswert?

Es ging ja darum, den Code "unleserlich" zu schreiben ;-)

Deswegen habe ich gerade nochmal eine Variante erstellt, die 
ausschließlich statisch arbeitet, d.h. sie ist das direkte Äquivalent zu 
hardcoded if-stmts. Allerdings immer noch mit dem Vorteil der 
unterschiedlichen Intervallarten und Datentypen.
1
#include <algorithm>
2
#include <array>
3
#include <utility>
4
#include <optional>
5
#include <util/algorithm.h>
6
#include <util/meta.h>
7
8
struct RightOpen;
9
struct LeftOpen;
10
struct Closed;
11
struct Open;
12
13
struct Adjacent;
14
struct Disjoint;
15
16
template<typename Kind, typename Lower, typename Upper>
17
struct StaticInterval {
18
    typedef Kind kind_type;
19
    typedef Lower lower_type;
20
    typedef Upper upper_type;
21
    typedef typename Lower::value_type value_type;
22
    static_assert(std::is_same_v<typename upper_type::value_type, value_type>, "different value types not possible");
23
    static constexpr bool includes (value_type v) {
24
        if constexpr(std::is_same_v<kind_type, RightOpen>) {
25
            return (v >= lower_type::value) && (v < upper_type::value);
26
        }
27
        else {
28
            // ...
29
        }
30
    }
31
};
32
33
template<typename Kind, typename Upper>
34
struct StaticBoundary {
35
    typedef Kind kind_type;
36
    typedef Upper upper_type;
37
    typedef typename Upper::value_type value_type;
38
    static constexpr bool includes(value_type v) {
39
        if constexpr(std::is_same_v<kind_type, RightOpen>) {
40
            return (v < upper_type::value);
41
        }
42
        else {
43
            // ...
44
        }
45
    }
46
};
47
48
namespace detail {
49
    template<typename, typename> struct LUTConverter;
50
    template<typename... II, auto... NN>
51
    struct LUTConverter<Meta::List<II...>, std::index_sequence<NN...>> {
52
        typedef Meta::List<typename II::value_type...> value_types;
53
        typedef typename Meta::front<value_types> value_type;
54
        static_assert(Meta::all_same<value_type, value_types>::value, "all intervals must use same value type");
55
        template<typename F>
56
        static constexpr void convert(value_type value, const F& f) {
57
            ((II::includes(value) ? (f(value_type(NN)), false) : true) && ...);
58
        }        
59
    };
60
}
61
62
template<typename Kind, typename Arrangement, typename T, T... Values>
63
struct Lookup {
64
    static_assert([]{
65
        T values[] = {Values...};
66
        for(size_t i = 0; i < (sizeof...(Values) - 1); ++i) {
67
            if (values[i] > values[i + 1]) {
68
                return false;
69
            }
70
        }
71
        return true;
72
    }(), "use ascending order");
73
    static_assert(sizeof...(Values) > 0, "at least one value required");
74
75
    using value_list = Meta::List<std::integral_constant<T, Values>...>;
76
    using lower_list = Meta::pop_back<value_list>;
77
    using upper_list = Meta::pop_front<value_list>;
78
    
79
    template<typename L, typename U>
80
    using buildInterval = StaticInterval<Kind, L, U>;
81
    
82
    using intervals = Meta::transform2<buildInterval, lower_list, upper_list>;
83
    using converterI = detail::LUTConverter<intervals, std::make_index_sequence<Meta::size<intervals>::value>>;
84
    
85
    template<typename U>
86
    using buildBoundary = StaticBoundary<Kind, U>;
87
    
88
    using boundaries = Meta::transform<buildBoundary, upper_list>;
89
    
90
    using converterB = detail::LUTConverter<boundaries, std::make_index_sequence<Meta::size<boundaries>::value>>;
91
    
92
    template<typename F>
93
    static constexpr void convert(T value, const F& f) {
94
        if constexpr(std::is_same_v<Arrangement, Disjoint>) {
95
            converterI::convert(value, f);
96
        }
97
        else if constexpr(std::is_same_v<Arrangement, Adjacent>) {
98
            converterB::convert(value, f);
99
        }
100
        else {
101
            static_assert(Meta::always_false<T>::value);
102
        }
103
    }
104
};
105
106
namespace Tests {
107
    static_assert([]{
108
        uint8_t result = -1;
109
        using lut = Lookup<RightOpen, Adjacent, uint8_t, 0, 10, 20, 40, 80, 160>;
110
        lut::convert(156, [&](auto index){result = index;});
111
        if (result != 5) return false;
112
        lut::convert(5, [&](auto index){result = index;});
113
        if (result != 1) return false;
114
        return true;
115
    }(), "test failed");    
116
}
117
118
volatile uint8_t result = -1;
119
volatile uint8_t value = 159;
120
121
int main() {
122
    using lut = Lookup<RightOpen, Adjacent, uint8_t, 0, 10, 20, 40, 80, 160>;
123
    lut::convert(value, [](auto index){result = index;});
124
}

Strengt Euch nicht an, das bei Euch zum Compilieren zu bekommen: es 
fehlt Euch die Meta-Programm-Bibliothek im namespace Meta. Aber 
vielleicht kann man trotzdem erkennen, was gemacht wird. Na ja, das 
Wesentliche ist eigentlich die zentrale fold-expression.

von Wilhelm M. (wimalopaan)


Lesenswert?

Carl D. schrieb:

>> Oh, seit 02.05.18 haben wir auch 8.1 released, der kann auch
>> familiar-template-syntax für generische lambdas. Das finde ich sehr
>> schön.
> Dann wird's noch schwieriger, denn dann wollen/müssen die ja auch noch
> den "Selbstbau"-Compiler dazu haben.

Im aktuellen MinGW ist doch aber auch der offizielle gcc 8.1 drin.

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Ich poste einfach mal den ganzen Code.

Na das ist ja ne ganze Menge Holz, was da zusätzlich benötigt wird.
Ich denke nicht, daß es sich lohnt, immer sofort ne Lib zu schreiben, 
die Aufgaben sind zu vielfältig.

Hier noch ein kleines praktisches Beispiel in plain C aus meiner 
Tastenabfrage mit ADC. Die Suchtabelle ist nichtlinear und wird mit dem 
Ohmschen Gesetz berechnet. Es wird die Bitstelle der gedrückten Taste 
ermittelt.
1
#include <avr/pgmspace.h>
2
3
#define RVCC    10.0    // 10k to VCC
4
#define RROW    1.0     // 1k between rows
5
#define RCOL    3.9     // 3k9 between colums
6
#define NROW    4       // number of rows
7
#define ADCRES  256     // ADC resolution
8
#define NKEY    12
9
10
#define ADCVAL(n)       ADCRES*(1-RVCC/((n)%NROW*RROW+(n)/NROW*RCOL+RVCC))
11
12
#define THRESHOLD(n)    (uint16_t)((ADCVAL(n)+ADCVAL(n+1))/2)
13
14
prog_uint8_t THRESHOLDS[] = {   THRESHOLD(11),
15
                                THRESHOLD(10),
16
                                THRESHOLD(9),
17
                                THRESHOLD(8),
18
                                THRESHOLD(7),
19
                                THRESHOLD(6),
20
                                THRESHOLD(5),
21
                                THRESHOLD(4),
22
                                THRESHOLD(3),
23
                                THRESHOLD(2),
24
                                THRESHOLD(1),
25
                                THRESHOLD(0),
26
                                0 };          // end of table
27
28
uint16_t key_no( uint8_t adcval )
29
{
30
  uint16_t num = 1<<NKEY;
31
  prog_uint8_t * thr = THRESHOLDS;
32
33
  while( adcval < pgm_read_byte( thr )){
34
    thr++;
35
    num >>= 1;
36
  }
37
  return num & ~(1<<NKEY);
38
}
An Code ergibt das 44 Bytes.
Beitrag "Tastenmatrix auslesen über nur 2 Leitungen"

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Aber: schreibst Du keine Bibliotheken für Deine Projekte bzw.
> Anwendungsdomäne?

Doch, nur ich habe mir (aus gutem Grund) abgewöhnt, Funktionen oder
Klassen mit Zusatzfeatures zu schreiben, deren spätere Verwendung
ungewiss ist. Anders ausgedrückt, produziere ich keinen Code "auf
Halde". In deinem Beispiel wäre die Option Disjoint so ein Fall. Da
mir dafür kein konkretes Anwendungsbeispiel einfällt, würde ich das
Feature auch nicht implementieren.

Wilhelm M. schrieb:
> Du bist enttäuscht, dass die libstdc++ dafür keine mundgerechte Lösung
> parat hat? Man könnte es mit adjacent_find<>() machen

adjacent_find passt wohl nicht so richtig für das Problem des TE, aber
was spricht gegen find_if? Für die Zukunft schöner fände ich find_if
aus experimental/ranges/algorithm, da man dort das Array mit den
Schwellwerten direkt (ohne den hässlichen Umweg über den first- und
last-Iterator) übergeben kann.

> ... allerdings ist das nicht constexpr, was ja hier hilfreich wäre.

Das empfinde ich nicht als Nachteil, das der zu untersuchende Wert (beim
TE output_mV) i.Allg. sowieso variabel ist.

Wilhelm M. schrieb:
>> Wilhelm M. schrieb:
>>> a) benutze Algorithmen / Funktionen, keine expl. Iterationen
>>
>> Wilhelm M. schrieb:
>>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>>         ...
>>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>>         ...
>>>         for(typename Limits::size_type n = 0; n < in.size(); ++n) {
>>>         ...
>
> Dies bezieht sich immer auf den Code der Klienten. Wie meinst Du denn,
> ist z.B. ein std::copy<>() implementiert?

Für mich ist eine Iteration nur dann implizit, wenn ich sie nicht selber
geschrieben habe. Aus der Sicht des TE, der deinen Code benutzt, sind
die Iterationen tatsächlich implizit. Als du dieses schriebst:

Wilhelm M. schrieb:
> a) benutze Algorithmen / Funktionen, keine expl. Iterationen

hatte der TE aber noch gar keinen Zugriff auf deinen Code, weswegen er
die Funktionen selber implementieren hätte müssen. Damit wären die
Iterationen für ihn explizit, denn alleine das Verlagern einer Iteration
in einen anderen Code-Abschnitt macht diese noch lange nicht implizit.

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Strengt Euch nicht an, das bei Euch zum Compilieren zu bekommen:

Das war auch nur der Versuch, anhand des Assemblerlistings 
herauszufinden, was Dein Programm eigentlich macht. Beim Lesen der 
Sourcen erschließen sich mir nur wenige Teilaspekte, aber nicht der 
eigentliche Ablauf.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:

> Hier noch ein kleines praktisches Beispiel in plain C aus meiner
> Tastenabfrage mit ADC. Die Suchtabelle ist nichtlinear und wird mit dem
> Ohmschen Gesetz berechnet. Es wird die Bitstelle der gedrückten Taste
> ermittelt.

Ich habe Deinen Code mal ergänzt zu:
1
#define __PROG_TYPES_COMPAT__
2
3
#include <stdint.h>
4
#include <avr/pgmspace.h>
5
6
#define RVCC    10.0    // 10k to VCC
7
#define RROW    1.0     // 1k between rows
8
#define RCOL    3.9     // 3k9 between colums
9
#define NROW    4       // number of rows
10
#define ADCRES  256     // ADC resolution
11
#define NKEY    12
12
13
#define ADCVAL(n)       ADCRES*(1-RVCC/((n)%NROW*RROW+(n)/NROW*RCOL+RVCC))
14
15
#define THRESHOLD(n)    (uint16_t)((ADCVAL(n)+ADCVAL(n+1))/2)
16
17
const prog_uint8_t THRESHOLDS[] = {   THRESHOLD(11),
18
                                THRESHOLD(10),
19
                                THRESHOLD(9),
20
                                THRESHOLD(8),
21
                                THRESHOLD(7),
22
                                THRESHOLD(6),
23
                                THRESHOLD(5),
24
                                THRESHOLD(4),
25
                                THRESHOLD(3),
26
                                THRESHOLD(2),
27
                                THRESHOLD(1),
28
                                THRESHOLD(0),
29
                                0 };          // end of table
30
31
#if 0
32
uint16_t key_no( uint8_t adcval ) {
33
  uint16_t num = 1<<NKEY;
34
  const prog_uint8_t * thr = THRESHOLDS;
35
36
  while( adcval < pgm_read_byte( thr )){
37
    thr++;
38
    num >>= 1;
39
  }
40
  return num & ~(1<<NKEY);
41
}
42
#else
43
uint8_t key_no( uint8_t adcval ) {
44
  uint8_t num = 0;
45
  const prog_uint8_t * thr = THRESHOLDS;
46
47
  while( adcval < pgm_read_byte( thr )){
48
    thr++;
49
    num++;
50
  }
51
  return num ;
52
}
53
#endif
54
55
volatile uint8_t value = 100;
56
volatile uint8_t result = -1;
57
58
int main() {
59
    result = key_no(value);
60
}

und habe meinen Code darauf abgestellt:
1
struct Generator {
2
    typedef Boundary<uint8_t, RightOpen> boundary_type;
3
    inline static constexpr double rvcc = 10.0;
4
    inline static constexpr double rrow = 1.0;
5
    inline static constexpr double rcol = 3.9;
6
    inline static constexpr uint8_t nrow = 4;
7
    inline static constexpr uint16_t adcres = 256;
8
    inline static constexpr uint8_t nkey = 12;
9
    
10
    constexpr auto& operator()() const {
11
        return bounds;
12
    }
13
14
    inline static constexpr auto bounds = []{
15
        std::array<boundary_type, 11> bs;
16
        auto adcval = [](size_t i){
17
            return adcres * (1-rvcc/((i)%nrow*rrow+(i)/nrow*rcol+rvcc));
18
        };
19
        for(size_t i = 0; i < bs.size; ++i) {
20
            auto threshold = (uint16_t)((adcval(i)+adcval(i+1))/2);
21
            bs[i] = threshold;
22
        }
23
        return bs;
24
    }();
25
};
26
27
volatile uint8_t result = -1;
28
volatile uint8_t value = 100;
29
30
int main() {
31
    using lut = Converter<Generator>::pgm_type;
32
    lookup(value, lut{}, [](auto index){result = index;});
33
}

Wie Du siehst, habe ich einmal genau Deinen Code mit der Taste als 
Bit-Muster und einmal eine günstigere Variante mit der Taste als Nummer 
erstellt.

Hier die Zahlen jeweils bezogen auf AVR m328:
Meine Variante   : 192 flash, 2 data
Deine Variante i : 210 flash, 2 data
Deine Variante ii: 214 flash, 2 data

Bei mir erstellt Converter<> mit Hilfe des Generator ein 
PgmArray<Boundary<uint8_t, RightOpen>>. Wie der Name schon sagt, liegen 
die Daten des PgmArray im ProgMem des AVR.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Wilhelm M. schrieb:
>> Du bist enttäuscht, dass die libstdc++ dafür keine mundgerechte Lösung
>> parat hat? Man könnte es mit adjacent_find<>() machen
>
> adjacent_find passt wohl nicht so richtig für das Problem des TE,

Passt genau, wenn man unzusammenhängende Intervalle hat (Option 
Disjoint). Falls man in dem Beispiel von Peter D. noch eine Hysterese 
einbauen wollte.

> aber
> was spricht gegen find_if?

Passt nur für zusammenhängende Intervalle.

> Für die Zukunft schöner fände ich /find_if/
> aus experimental/ranges/algorithm, da man dort das Array mit den
> Schwellwerten direkt (ohne den hässlichen Umweg über den first- und
> last-Iterator) übergeben kann.

Das ist ein Einzeiler wenn es nur um die Iteratoren geht.

>> ... allerdings ist das nicht constexpr, was ja hier hilfreich wäre.
>
> Das empfinde ich nicht als Nachteil, das der zu untersuchende Wert (beim
> TE output_mV) i.Allg. sowieso variabel ist.

constexpr schränkt das ja auch nicht ein, es bietet eben nur die 
Möglichkeit in einem constexpr-Kontext.

> Für mich ist eine Iteration nur dann implizit, wenn ich sie nicht selber
> geschrieben habe. Aus der Sicht des TE, der deinen Code benutzt, sind
> die Iterationen tatsächlich implizit. Als du dieses schriebst:
>
> Wilhelm M. schrieb:
>> a) benutze Algorithmen / Funktionen, keine expl. Iterationen
>
> hatte der TE aber noch gar keinen Zugriff auf deinen Code, weswegen er
> die Funktionen selber implementieren hätte müssen. Damit wären die
> Iterationen für ihn explizit, denn alleine das Verlagern einer Iteration
> in einen anderen Code-Abschnitt macht diese noch lange nicht implizit.

Jein. Wenn er es wie gesagt in eine (eigene) Bibliothek mit 
entsprechenden Tests, etc. auslagern würde, dann wäre es auch dort 
implizit. Du kannst auch Klient Deines eigenen Codes sein. Das passiert 
ja manchmal auch auf Umwegen.

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Bei mir erstellt Converter<> mit Hilfe des Generator ein ...

???
Ich hab nicht die geringste Idee, welche Zeile das Array definiert und 
wo die Schleife mit dem Vergleich auf "<" ist.
Und da ich es ja eh nichtmal compiliert werden kriege, bleibe ich wohl 
besser bei plain C.

Ich nehme mal an, zum Compilieren ist noch ne riesen Latte von Deinen 
speziellen Headern nötig, die Du leider nicht angegeben hast.
Mein Code war vollständig, d.h. er compiliert ohne weitere Header.

: Bearbeitet durch User
Beitrag #5444962 wurde von einem Moderator gelöscht.
von Peter D. (peda)


Lesenswert?

An plain C mag ich, daß es gut dokumentiert ist, z.B. wenn ich nach 
scanf, printf usw. google.
Suche ich dagegen nach Converter, Generator, RightOpen usw., kann mir 
Google nicht helfen. Das macht es natürlich schwer, solche 
Schlüsselwörter zu benutzen.

Beitrag #5445003 wurde von einem Moderator gelöscht.
von Oliver S. (oliverso)


Lesenswert?

Peter D. schrieb:
> Suche ich dagegen nach Converter, Generator, RightOpen usw., kann mir
> Google nicht helfen. Das macht es natürlich schwer, solche
> Schlüsselwörter zu benutzen.

Das sind auch keine Schlüsselworte, sondern selbstgeschriebene 
Funktionen. Da kann dir Google wirklich nicht weiterhelfen.

Oliver

von Dr. Sommer (Gast)


Lesenswert?

Hier ist eine Variante von Peters Code die mittels Metaprogrammierung 
das Array berechnet. Der Hauptvorteil besteht hier darin, dass man durch 
eine einzige Zahl die Anzahl der Einträge bestimmen kann, und man die 
genLUT-Funktion auch problemlos für beliebige andere LUT's recyclen 
kann. Eleganter wär's noch die Zahlen nicht als globale Konstanten zu 
übergeben sondern z.B. als template-Parameter an treshold; das sei als 
Übung dem Leser überlassen :)
Der Code ist vollständig und mit C++14 kompilierbar. Selbstverständlich 
ist auch C++ dokumentiert (nicht nur im Standard), und alle Dinge die 
hier nicht im Code definiert sind kann man Googlen:
1
#include <iostream>
2
#include <utility>
3
#include <array>
4
#include <cstddef>
5
#include <cstdint>
6
7
static constexpr double RVCC =   10.0;    // 10k to VCC
8
static constexpr double RROW =   1.0;     // 1k between rows
9
static constexpr double RCOL =   3.9;     // 3k9 between colums
10
static constexpr std::size_t NROW  =  4;       // number of rows
11
static constexpr uint32_t ADCRES = 256;     // ADC resolution
12
static constexpr uint8_t NKEY  =  12;
13
14
constexpr double adcval(std::uint8_t n) {
15
  return ADCRES*(1-RVCC/((n)%NROW*RROW+(n)/NROW*RCOL+RVCC));
16
}
17
18
constexpr double treshold(std::size_t n) {
19
  return (uint16_t)((adcval(n)+adcval(n+1))/2);
20
}
21
22
template <std::size_t N, typename F, std::size_t... I>
23
constexpr auto genLUT2 (F f, std::index_sequence<I...>) -> std::array<decltype (f (0)), N> {
24
  return {{ f (N-I) ... }};
25
}
26
27
template <std::size_t N, typename F>
28
constexpr auto genLUT (F f) -> std::array<decltype (f (0)), N> {
29
  return genLUT2<N, F> (std::forward<F> (f), std::make_index_sequence<N> {});
30
}
31
32
constexpr auto THRESHOLDS = genLUT<12> (treshold);
33
34
int main() {
35
  for (const auto& val : THRESHOLDS) {
36
    std::cout << val << ", ";
37
  }
38
  std::cout << std::endl;
39
  return 0;
40
}
Die 0 am Ende des Arrays hab ich weggelassen; ich finde es eleganter per 
THRESHOLDS.size() die Größe explizit abzufragen, so stören auch 
gewünschte Nullen im Array nicht.

von Peter D. (peda)


Lesenswert?

Oliver S. schrieb:
> Das sind auch keine Schlüsselworte, sondern selbstgeschriebene
> Funktionen.

Das hatte ich mir schon gedacht. Dann sind aber Codebeispiele ohne die 
benötigten Funktionsdefinitionen ziemlich sinnlos. Beispiele sollten 
schon nachvollziehbar sein.

von A. S. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Das ist eher Spaghetti Code. Gerade bei großen Projekten sollten
> Funktionen nicht so lang werden. Besser ist es, viele kleine Funktionen
> (ca 10 Zeilen) zu haben, die genau einen Aspekt bearbeiten und alles
> andere ggf. delegieren.
Wenn 1E6-Zeilen in 100 Treiber zu je 1E4 Zeilen zerfallen, hast Du 
recht. Ich vermute, du redest von so was.


> Diese typischen Riesen-Algorithmen in Anfänger-Code lassen sich meist
> in viele kleine Einheiten aufteilen.
Auch das stimmt. Davon ist bei mir aber nicht die Rede.

> Die kann man dann auch wieder verwenden.
Auch das stimmt. Aber was soll das?

Das man eine Aufgabe auf verschiedene Arten beleuchten soll um Synergien 
und Vereinfachungen zu finden, sicher. Aber irgendwie anzunehmen, dass 
komplexe Dinge (und nur um die geht es hier) einfacher werden, wenn ich 
sie aus ihrem Kontext reiße und diesen mnühsam wieder herstelle (bzw. 
muss), zeigt doch nur, dass Du die Straße vermutlich noch nie gegangen 
bist. Also nichts für ungut.

von Dr. Sommer (Gast)


Lesenswert?

Achim S. schrieb:
> Wenn 1E6-Zeilen in 100 Treiber zu je 1E4 Zeilen zerfallen, hast Du
> recht. Ich vermute, du redest von so was.

Nö, auch von monolithischen Projekten. Auch da braucht man keine 
1000-Zeilen-Funktionen. Die lassen sich zu 99% in handlichere Funktionen 
aufteilen. Und wenn das einen "Kontext zerreißt" sind die Daten-und 
Programmstrukturen wohl nicht gut konstruiert.

Achim S. schrieb:
> zeigt doch nur, dass Du die Straße vermutlich noch nie gegangen
> bist. Also nichts für ungut.

Ad Hominem, ich hör dir trappsen. Ja, ich hab auch mal Spaghetti-Code 
geschrieben. Vor >10 Jahren... :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Hier ist eine Variante von Peters Code die mittels Metaprogrammierung
> das Array berechnet. Der Hauptvorteil besteht hier darin, dass man durch
> eine einzige Zahl die Anzahl der Einträge bestimmen kann, und man die
> genLUT-Funktion auch problemlos für beliebige andere LUT's recyclen
> kann.

Warum nicht C++17? Dann sind lambdas (automatisch) constexpr. Da geht 
das alles viel einfacher.
1
#include <iostream>
2
#include <utility>
3
#include <array>
4
#include <cstddef>
5
#include <cstdint>
6
7
static constexpr double RVCC =   10.0;    // 10k to VCC
8
static constexpr double RROW =   1.0;     // 1k between rows
9
static constexpr double RCOL =   3.9;     // 3k9 between colums
10
static constexpr std::size_t NROW  =  4;       // number of rows
11
static constexpr uint32_t ADCRES = 256;     // ADC resolution
12
static constexpr uint8_t NKEY  =  12;
13
14
constexpr double adcval(std::uint8_t n) {
15
  return ADCRES*(1-RVCC/((n)%NROW*RROW+(n)/NROW*RCOL+RVCC));
16
}
17
18
constexpr double treshold(std::size_t n) {
19
  return (uint16_t)((adcval(n)+adcval(n+1))/2);
20
}
21
22
constexpr auto THRESHOLDS = []<auto N = 12>(auto f){
23
    std::array<decltype(f(0)), N> data{};
24
    for(size_t i = 0; i < N; ++i) {
25
        data[i] = f(i);
26
    }
27
    return data;
28
}(treshold);
29
30
int main() {
31
  for (const auto& val : THRESHOLDS) {
32
    std::cout << val << ", ";
33
  }
34
  std::cout << std::endl;
35
  return 0;
36
}

Allerdings haben wir damit nur die Tabelle, noch keine Verwendung dieser 
als Intervallbildner oder unterschiedliche Intervallarten (was ich oben 
gepostet hatte).
Macht man dieses Beispiel etwa auch noch auf einem AVR, so landet die 
Tabelle im RAM, entweder im data-segment oder auf dem Stack (als local 
object). Deswegen habe ich oben mit einem PgmArray gearbeitet.

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Warum nicht C++17? Dann sind lambdas (automatisch) constexpr. Da geht
> das alles viel einfacher.
Naja, die Idee war ja schon die Funktion genLUT wiederverwendbar zu 
machen... :) Und das ging in C++14 halt auch. Keil und Konsorten können 
auch kein C++17...

Wilhelm M. schrieb:
> Allerdings haben wir damit nur die Tabelle,
Peter's Funktion ließe sich damit direkt problemlos nutzen. Wollte sie 
nur nicht kopieren.

Wilhelm M. schrieb:
> Macht man dieses Beispiel etwa auch noch auf einem AVR, so landet die
> Tabelle im RAM, entweder im data-segment oder auf dem Stack (als local
> object). Deswegen habe ich oben mit einem PgmArray gearbeitet.
Ja, sowas braucht man da auch, aber ich kenn mich mit der ganzen 
AVR-Progmem-Geschichte nicht so aus, bin zu verwöhnt von ARM :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Peter D. schrieb:
>> Suche ich dagegen nach Converter, Generator, RightOpen usw., kann mir
>> Google nicht helfen. Das macht es natürlich schwer, solche
>> Schlüsselwörter zu benutzen.
>
> Das sind auch keine Schlüsselworte, sondern selbstgeschriebene
> Funktionen. Da kann dir Google wirklich nicht weiterhelfen.

Wenn ich nach key_no aus Peters Code google, finde ich auch nichts 
passendes ;-)

Funktionen sind es in der Tat nicht, sondern:

Converter ist ein Klassen-Template

Generator ist eine Klasse, geschrieben als Funktor

RightOpen, LeftOpen, ... Adjacent, ... sind Klassen gebraucht aus sog. 
Tag-Typen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Warum nicht C++17? Dann sind lambdas (automatisch) constexpr. Da geht
>> das alles viel einfacher.
> Naja, die Idee war ja schon die Funktion genLUT wiederverwendbar zu
> machen... :) Und das ging in C++14 halt auch. Keil und Konsorten können
> auch kein C++17...

Au weia, schlafen die alle?

> Wilhelm M. schrieb:
>> Allerdings haben wir damit nur die Tabelle,
> Peter's Funktion ließe sich damit direkt problemlos nutzen. Wollte sie
> nur nicht kopieren.

Na ja, sollt eman umbauen, damit das Sentinel 0 nicht stört.

> Wilhelm M. schrieb:
>> Macht man dieses Beispiel etwa auch noch auf einem AVR, so landet die
>> Tabelle im RAM, entweder im data-segment oder auf dem Stack (als local
>> object). Deswegen habe ich oben mit einem PgmArray gearbeitet.
> Ja, sowas braucht man da auch, aber ich kenn mich mit der ganzen
> AVR-Progmem-Geschichte nicht so aus, bin zu verwöhnt von ARM :)

Ich wollte es nur erwähnen, sonst gibt es gleich wieder großes Geschrei 
... und wie gesagt, auch dafür gibt es eine Lösung.

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Au weia, schlafen die alle?

Die entwickeln halt lieber "wichtige" Dinge weiter wie die 
Klicki-Bunti-GUI. Im Embedded Bereich ist C++ ja eh verteufelt. Da bin 
ich froh dass sie es bis C++14 geschafft haben... Selbst MSVC kann C++17 
noch nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Au weia, schlafen die alle?
>
> Die entwickeln halt lieber "wichtige" Dinge weiter wie die
> Klicki-Bunti-GUI. Im Embedded Bereich ist C++ ja eh verteufelt. Da bin
> ich froh dass sie es bis C++14 geschafft haben... Selbst MSVC kann C++17
> noch nicht.

Hier sieht es aber bzgl. MSCV ganz gut aus:

https://en.cppreference.com/w/cpp/compiler_support

Keil könnte sich ja das frontend von EDG kaufen - das machen einige auch 
für ihre IDEs.

von Karl (Gast)


Lesenswert?

Bei allem Respekt vor euren c++ Kenntnissen, auf die ich schon ein 
bisschen neidisch bin: was nützt es, geilen Code zu schreiben, der nur 
von 10% der potentiellen Kollegen verstanden wird? Ich benutze auch 
gerne einen Teil von c++, aber da ich ab und zu ein Produkt ausliefern, 
weiter entwickeln oder gar warten muss, habe ich leider nicht in dem 
Maße Zeit mich in neue c++e einzuarbeiten. Ich verstehe leider 
vornehmlich Bahnhof.

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Hier sieht es aber bzgl. MSCV ganz gut aus:

Aha, das ist ganz neu - jetzt auch mit fold expressions und 
template-auto. Gut zu wissen, dann kann ich meinen C++17 Code damit mal 
testen.

Hier steht mehr dazu:
https://blogs.msdn.microsoft.com/vcblog/2018/05/07/announcing-msvc-conforms-to-the-c-standard/

Karl schrieb:
> was nützt es, geilen Code zu schreiben, der nur
> von 10% der potentiellen Kollegen verstanden wird?
Es gibt Kollegen die können C++. Das gleiche Problem hat man doch mit 
allen Tools und Sprachen - von Assembler bis Prolog. Das ist kein 
prinzipielles Problem von C++. Bei meinem AG ist C++ die Hauptsprache, 
neben einer ganzen Reihe weiterer.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Wilhelm M. schrieb:
> u = o = 0;
> if (output_mv < 400) u = (o = (output_mv / 100) * 2 + 2) + 1;

warum nicht gleich als einzeiler!?

if (u = o = 0, output_mv < 400) u = (o = (output_mv / 100) * 2 + 2) + 1;


Mark W. schrieb:
> if(output_mV > 199 && output_mV < 300)
> {
>     o = 8;
>     u = 9;
> }
>
> if(output_mV > 299 && output_mV < 400)
> {
>     o = 10;
>     u = 11;
> }

so etwas würde ich immer "verdichten", ich hasse dieses sinnlose 
klammern von "einzeiler" und auch die bedingung sinniger hinschreiben.

if (200 <= output_mV && output_mV < 300) o = 8, u = 9;
else if (300 <= output_mV  && output_mV < 400) o = 10, u = 11;


mt

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Karl schrieb:
> was nützt es, geilen Code zu schreiben, der nur
> von 10% der potentiellen Kollegen verstanden wird?

Zumal die 30 Originalzeilen (bei Blocksatz) gut lesbar sind.

Das C++ laufzeittechnisch super effektiv ist, für solche Dinge besser 
als jede andere Sprache, geschenkt.

Bei solchen Beispielen wird klar, warum Funktion mit mehr als 10 Zeilen 
böse sind und Unittests unverzichtbar.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Es gibt Kollegen die können C++.

Ja. Aber Wilhelm meint offenbar, man könnte auch als "normaler" 
C-Programmierer ratzfatz auf C++ umsteigen. Dabei versucht er, mit 
Tonnen von sehr fortgeschrittenem (aber leider auch unvollständigen und 
damit oft nicht compilierbaren) C++17-Code sogar C-Anfänger für C++ 
umzustimmen.

Dass er mit seinen Beispielen, die eher wie Kanonen auf Spatzen wirken, 
einen potentiellen C-nach-C++-Umsteiger eher abschreckt, scheint er 
absolut zu ignorieren.

Peter (peda), der bekanntermaßen schon seit Jahren viele gute 
C-Programme hier im Forum vorstellt und damit auch als C-Experte hier 
bekannt ist, hat ja oben geschrieben, dass er bei Wilhelms Code nur noch 
Bahnhof versteht. Dabei hat er vorher guten Willen gezeigt, Wilhelms 
Code auch zu verstehen und auch nachzuvollziehen.

Wilhelm ignoriert das einfach und versucht gar nicht erst, Peters 
Bedenken und Zweifel durch entsprechende Erklärungen und Hilfestellungen 
zu zerstreuen - ganz im Gegenteil: Er ignoriert einfach Peters Beiträge, 
um stattdessen auf Dr. Sommers Variante eine noch komplexere 
C++-17-Version oben draufzulegen.

@Wilhelm: Warum gehst Du auf Peters Verständnisprobleme erst gar nicht 
ein? Der einzige Eindruck, den Du damit hinterlässt: Du kaperst 
C-Anfänger-Probleme-Threads, um dann C++ den Leuten madig zu machen, 
indem Du möglichst komplexe Beispiele postest.

Warum zäumst Du das Pferd von hinten auf, statt in mehreren Schritten 
vom einfachen Beispiel letztendlich zur eleganten Variante zu kommen? 
Dann könnte man Deine Gedankengänge wenigstens nachvollziehen.

Voraussetzung ist natürlich:

- Angabe des Compilers
- Angabe der C++-Version (also bei Dir 17)
- Vollständig compilierbarer Code

Um möglichst viele Leute zu erreichen, wäre es auch nicht gerade dumm, 
bei der C++-Version eher Abstriche zu machen und auch mal zu C++14 (oder 
älter) zurückzugehen, wie es Dr. Sommer gemacht hat. Nicht jeder hat den 
neuesten GCC auf seinem Rechner.

Aber so, wie Du das machst, wird das nichts. Solange Du einfach die 
Leute ignorierst, die ihre Verständnisprobleme äußern und damit auch 
Hilfestellungen Deinerseits erwarten, machst Du denen C++ nicht gerade 
schmackhaft. Leider erreichst Du mit Deiner "Mission" das Gegenteil, 
welches Du vermeintlich zu erreichen suchst.

von Wilhelm M. (wimalopaan)


Lesenswert?

Karl schrieb:
> Bei allem Respekt vor euren c++ Kenntnissen, auf die ich schon ein
> bisschen neidisch bin: was nützt es, geilen Code zu schreiben, der nur
> von 10% der potentiellen Kollegen verstanden wird? Ich benutze auch
> gerne einen Teil von c++, aber da ich ab und zu ein Produkt ausliefern,
> weiter entwickeln oder gar warten muss, habe ich leider nicht in dem
> Maße Zeit mich in neue c++e einzuarbeiten. Ich verstehe leider
> vornehmlich Bahnhof.

Das erinnert an die viel zitierte Geschichte vom Förster und Holzfäller 
...

Eine sehr einfaches, gut machbares, für jeden erreichbares und in jeder 
Firma durchführbares Hilfsmittel sind das, was man früher "Standups" 
nannte, die hier mal als Dailies bezeichnet werden:

https://www.fluentcpp.com/2017/04/04/the-dailies-a-new-way-to-learn-at-work

von Nop (Gast)


Lesenswert?

Frank,

ich hatte heute zweimal geschrieben, daß es bei Wilhelms Code normal 
ist, wenn er aus einfachen Sachen Code macht, der in keiner Weise mehr 
nachvollziehbar ist. Schließlich ist das jetzt in mehreren Threads schon 
so gewesen. Und daß so eine Praxis reiner Wegwerfcode ist, weil 
spätestens der Maintenanceprogrammierer danach das nicht mehr 
durchdringen wird.

Beidemale hat einer Deiner Moderatorkollegen das kommentarlos gelöscht, 
obwohl es genau darauf hinausläuft, was Du jetzt selber als Moderator 
schreibst. Wieso?

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:

> Peter (peda), der bekanntermaßen schon seit Jahren viele gute
> C-Programme hier im Forum vorstellt und damit auch als C-Experte hier
> bekannt ist, hat ja oben geschrieben, dass er bei Wilhelms Code nur noch
> Bahnhof versteht.

Ja, das war sein Kommentar zum ersten Post von Dr. Sommer. Danach kam 
allerdings keine konkrete Frage mehr.

> Wilhelm ignoriert das einfach und versucht gar nicht erst, Peters
> Bedenken und Zweifel durch entsprechende Erklärungen und Hilfestellungen
> zu zerstreuen - ganz im Gegenteil:

Fragen will auch gelernt sein.

> @Wilhelm: Warum gehst Du auf Peters Verständnisprobleme erst gar nicht
> ein?

Dazu sollte er mal eine konkrete Frage stellen. Bahnhof reicht nicht. 
Wer keine konkrete Frage stellen kann, hat sich nicht damit 
auseinandergesetzt.

> Voraussetzung ist natürlich:
>
> - Angabe des Compilers
> - Angabe der C++-Version (also bei Dir 17)
> - Vollständig compilierbarer Code

Malen nach Zahlen führt kaum zu einem Erkenntnisgewinn (und wird hier in 
dem Forum ja gerne als Arduino-like bezeichnet). Man liest sich den Code 
durch und stößt auf etwas unbekanntes. Dann schaut man selbständig mal 
nach was das sein könnte und konstruiert in seinem Umfeld mit seinen 
Bezeichnern, etc. ein eigenes Beispiel. Wenn das nicht funktioniert, 
dann kann nachfragen. Aber man muss schon eine Frage haben.

> Um möglichst viele Leute zu erreichen, wäre es auch nicht gerade dumm,
> bei der C++-Version eher Abstriche zu machen und auch mal zu C++14 (oder
> älter) zurückzugehen, wie es Dr. Sommer gemacht hat. Nicht jeder hat den
> neuesten GCC auf seinem Rechner.

Im Interesse der Weiterbildung könnte man aber mal einen neueren dazu 
installieren. Richtet ja keinen Schaden an.

> Aber so, wie Du das machst, wird das nichts. Solange Du einfach die
> Leute ignorierst, die ihre Verständnisprobleme äußern und damit auch
> Hilfestellungen Deinerseits erwarten, machst Du denen C++ nicht gerade
> schmackhaft. Leider erreichst Du mit Deiner "Mission" das Gegenteil,
> welches Du vermeintlich zu erreichen suchst.

Ich bin nicht angetreten, um zu missionieren. Wer das nicht interessant 
findet, soll es halt ignorieren. Die anderen können ja fragen. Aber das 
setzt natürlich voraus, dass man sich ausreichend mit den Dingen 
beschäftigt. Anschauen, zurücklehnen, erkennen, das man nichts versteht, 
Bahnhof sagen, und dann darauf warten, das es mundgerecht zerteilt wird: 
nein, so läuft das nicht. Das ist eine Anspruchshaltung, die auch im 
echten Leben nicht zum Erfolg führt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nop schrieb:
> Beidemale hat einer Deiner Moderatorkollegen das kommentarlos gelöscht,
> obwohl es genau darauf hinausläuft, was Du jetzt selber als Moderator
> schreibst. Wieso?

Weil du eine bloße Anschuldigung hingeworfen hast, ohne irgendeine
Argumentation, pure Behauptung.  (Unsinnige Behauptungen wie die über
den vorgeblichen „Maintenanceprogrammierer“ hast du dir ja selbst
diesmal nicht verkneifen können.)

Wenn du den riesigen Unterschied zwischen deinem „Beitrag“ und Yalus
recht ausführlicher und im Gegensatz zu dir durchaus sachlicher
Argumentation nicht siehst, sorry.

Merke: sowie in deinem Satz das Wort „immer“ als Beschreibung von
Verhaltensweisen eines anderen auftaucht, ist dieser eigentlich von
vornherein eine falsche Aussage, deren offenbar einziger Zweck dann
Polemik ist.

Jetzt lies dir bitte Yalus Argumentation nochmal durch.

von Nop (Gast)


Lesenswert?

Jörg W. schrieb:

> Weil du eine bloße Anschuldigung hingeworfen hast, ohne irgendeine
> Argumentation, pure Behauptung.

Mit anderen Worten, Du hast die Vorgeschichte in den anderen Threads 
nicht mitbekommen. Kann passieren, aber das hättest Du nachfragen 
können, statt einfach zu löschen. Abgesehen davon ist Franks Beitrag 
ebenfalls Behauptung, denn er verlinkt auch nicht auf die relevanten 
Threads im Sinne eines Quellennachweises.

Ich kann Dir ziemlich genau sagen, was der Unterschied ist: Frank ist 
auch Moderator und ich nicht.

> (Unsinnige Behauptungen wie die über
> den vorgeblichen „Maintenanceprogrammierer“ hast du dir ja selbst
> diesmal nicht verkneifen können.)

Das ist keine unsinnige Behauptung, sondern Realität in der Industrie. 
Wenn Du solche Projekte noch nicht erlebt hast, sei froh, aber 
klassifizier es nicht als Unsinn. Die Anführungszeichen deuten darauf 
hin, daß Du nicht einmal weißt, worum es geht.

Der Grundplot ist der, daß C++ zu komplex ist, als daß man ALLES 
verstehen könnte. Wenn man nun wahllos 10 Programmierer hat, die alle 
ihre 30% Verständnis mischen, dann muß der Maintenanceprogrammierer die 
Obermenge von all dem können muß UND darin auch noch die Bugs finden 
muß, die erst später auftreten.

Deswegen wird üblicherweise nur ein kleines Subset von C++ verwendet. 
Selbst bei C wird das so gemacht, deswegen gibt es ja MISRA-C.

von Karl ein anderer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das erinnert an die viel zitierte Geschichte vom Förster und Holzfäller
> ...

Meinst du die? 
https://www.motivate-yourself.de/geschichte-holzfaeller-waldarbeiter-saege-stumpf/

Da würde ich direkt widersprechen.  Es geht nicht nur darum, zu wenig 
Zeit zum Lernen zu haben, sondern diesen Zeitaufwand gegen die evtl 
nötige mehrarbeit ohne das gelernte und den langfristigen wert des codes 
abzuwägen.

Wenn alle Teilnehmer am Thread in einer Abteilung wären, könnte nur dr. 
Sommer deinen Code verwenden. Toll.

Offtopic: Dein Auftreten finde ich unangenehm und ein bisschen 
überheblich. Du scheinst zeigen zu wollen, wie gut du c++ beherrschst. 
Das ist gelungen.

von Karl (Gast)


Lesenswert?

Sorry, falscher Nick am Tablet.

von Heimlehrgangsprogrammierer (Gast)


Lesenswert?

Die gezeigten C++ Beispiele sehen ja alle recht tolle aus. Aber es kommt 
mir doch für die kleineren Sachen als etwas Overkill vor.

Wenn ichs mir richtig überlege, liebe ich Pedas Forum Codebeispiele. Die 
sind immer pure Essenz. Oft am Anfang schwer zu verstehen, dann als 
brilliant verstanden. Auch sind sie immer sehr Platz orientiert und 
passen gut auf kleine uC. Als Vorbild finde ich daher seinen 
Programmierstil und Ansatz sympatischer.

Das soll jetzt keine Kritik an C++ sein. Aber die Welt sollte groß genug 
sein, damit jedes Tierchen sein Pläsierchen finden kann. Nicht jeder der 
hier im Forum mitmacht ist ein SW Guru der damit seine Brötchen verdient 
und damit auch im Schlaf sicher wandelt. Wenn doch vielmehr ein breites 
Spektrum an Können in beiden Richtungen vorhanden ist.

Wenn man sich erinnert, daß C als ASM Ersatz in die Welt gerufen wurde, 
müßte man eigentlich zugeben, daß C dann schon ein wahrer Luxus ist, 
auch wenn man im neuesten C++ komplizierte Konstrukte einfacher in Code 
kleiden kann und mächtige Möglichkeiten hat. Naja, wer's kann und sich 
damit wohlfühlt und die Firma erwartet, daß man es kann, dann ist ja 
alles gut.

Deshalb plädiere ich, C trotzdem noch nicht ganz abzuschreiben. Viele 
Projekte können damit auch heutzutage noch bequem durchgezogen werden. 
Und wem C in Fleisch und Blut übergegangen ist, der wird oft mit 
esoterischen C++ sowieso lange keine Freude haben. Der Weg scheint 
zumindest mir als sehr steinig zu sein.


Mfg,
Ein Heimlehrgangsprogrammierer

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nop schrieb:

>> Weil du eine bloße Anschuldigung hingeworfen hast, ohne irgendeine
>> Argumentation, pure Behauptung.
>
> Mit anderen Worten, Du hast die Vorgeschichte in den anderen Threads
> nicht mitbekommen.

Die ist mir egal.  Hier geht es um dein Auftreten in diesem
Thread.  Das fiel für mich unter „vorsätzliche Störung des
Forenbetriebs“ (also: Trollbeitrag), da du eben einfach nur eine
bloße Behauptung provokativ hingeworfen hast.

> Kann passieren, aber das hättest Du nachfragen
> können, statt einfach zu löschen.

Wie soll ich bitteschön bei dir nachfragen, wenn du keine Mailadresse
angeben magst?

Sorry.  Genau dafür darf man auch bei anonymen Postings eine
Mailadresse hinterlegen: damit wir ggf. mal rückfragen können (jemand
anders sieht sie ja sowieso nicht).  Wenn jemand auf diese Möglichkeit
verzichtet, dann gehe ich davon aus, dass er an Rückfragen nicht
interessiert ist.

Solchen Käse wie den jetzt hier gerade im Thread breitzutreten, ist
für das Forum einfach nur lästig und auch vom Betreiber ausdrücklich
unerwünscht.

> Abgesehen davon ist Franks Beitrag
> ebenfalls Behauptung, denn er verlinkt auch nicht auf die relevanten
> Threads im Sinne eines Quellennachweises.

Franks (sorry, mit Yalu verwechselt, der war weiter oben aktiv) Beitrag
ist Argumentation, nicht nur eine hingeschmissene Behauptung.

Nochmal: wenn du den himmelweiten Unterschied zwischen deinem und
seinem Beitrag nicht siehst, dann tut es mir leid, aber dann wundere
dich nicht, wenn wir sowas ggf. auch mal als linienüberschreitend
empfinden und rauswerfen.

> Ich kann Dir ziemlich genau sagen, was der Unterschied ist: Frank ist
> auch Moderator und ich nicht.

Andersrum wird der Schuh draus: weil Frank eben bereits seit Jahren
mit einem guten Diskussionsstil aufgefallen ist, ist er Moderator
geworden.

>> (Unsinnige Behauptungen wie die über
>> den vorgeblichen „Maintenanceprogrammierer“ hast du dir ja selbst
>> diesmal nicht verkneifen können.)
>
> Das ist keine unsinnige Behauptung, sondern Realität in der Industrie.

Es ist alles mögliche Realität in der Industrie.

Das allein macht es nicht verallgemeinerungswürdig.  (Btw., auch ich
bin „in der Industrie“ tätig, ich weiß also auch, wovon wir reden.)

> Der Grundplot ist der, daß C++ zu komplex ist, als daß man ALLES
> verstehen könnte.

Das bestreitet gewiss keiner.

Anderen Sprachen geht das genauso.

Ich habe übrigens absolut nicht bestritten, dass ich Wilhelms
Programmbeispiele in der präsentierten Form nicht lehrreich finde;
wenn man sowas schon als Beispiel für andere hinschreiben will, dann
muss man es zumindest tiefergehend erläutern und/oder Kommentare
einfügen.

Es ging hier aber nicht um Inhalte, sondern die (also deine) Form
der Kritik.  Es ist eben ein großer Unterschied, ob man eine Kritik
sachlich rüberbringen kann, oder Worte wie „immer“ und „schreibt
gern write-only Code“ dafür benutzt.

> Deswegen wird üblicherweise nur ein kleines Subset von C++ verwendet.

Welches sich natürlich je nach Organisation unterscheiden kann.

> Selbst bei C wird das so gemacht, deswegen gibt es ja MISRA-C.

MISRA ist erstens nicht der Nabel der Industrie (sondern nur eines
Teils der Industrie), zweitens ja durchaus auch zumindest in Teilen
umstritten.

von Nop (Gast)


Lesenswert?

Jörg W. schrieb:

> Wie soll ich bitteschön bei dir nachfragen, wenn du keine Mailadresse
> angeben magst?

So, wie Du es jetzt gerade auch tust. Im Übrigen bin ich nicht der 
Einzige, dem es negativ auffällt, wenn Wilhelm öfter Threads mit 
C++-Gespamme kapert. Das passiert jetzt nicht zum erstenmal, so daß es 
mich schon überrascht, wenn Du davon noch gar nichts mitbekommen hast.

> Das allein macht es nicht verallgemeinerungswürdig.  (Btw., auch ich
> bin „in der Industrie“ tätig, ich weiß also auch, wovon wir reden.)

Maintenanceprogrammierer sind in der Industrie völlig normal. Mag sein, 
daß der Begriff auf deutsch nicht üblich ist, aber da ich mehr englisch 
als deutsch lese, fiel mir für "maintenance programmer" halt keine 
bessere Übersetzung ein.

Ist doch auch logisch. Während der aktiven Entwicklung braucht man eben 
deutlich mehr Entwickler. Irgendwann ist das Projekt aber fertig, dann 
geht es um Pflege, Bugfixes und Erweiterungen. Dafür stellt aber keine 
Firma mehr die volle Mannschaft hin, sondern das wird runtergefahren. 
Zudem nimmt man dafür typischerweise auch eher die neu eingestellten 
Leute.

> Es ging hier aber nicht um Inhalte, sondern die (also deine) Form
> der Kritik.  Es ist eben ein großer Unterschied, ob man eine Kritik
> sachlich rüberbringen kann, oder Worte wie „immer“ und „schreibt
> gern write-only Code“ dafür benutzt.

Wie gesagt, daß liegt daran, daß Wilhelm das in diesem Stil mit einiger 
Regelmäßigkeit tut, und nach demselben Muster. Lies Dir die Reaktionen 
doch durch hier. Wenn jemand versucht, über das Disassembly 
rauszukriegen, was der Code eigentlich tut, ist das geradezu die 
Definition von write-only-Code.

Ich mag mir gar nicht ausmalen, was für Code dabei wohl rauskäme, wenn 
der auch noch inhaltlich anspruchsvolle Funktionen erfüllen sollte.

Und nein, das liegt nicht zwingend an C++ an sich, sondern es zieht 
solche Leute nur verstärkt an. Der Code von Stockfish etwa, einer der 
stärksten Schach-Engines der Welt, ist auch in C++ und sieht trotzdem 
nicht so aus.

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Ich mag mir gar nicht ausmalen, was für Code dabei wohl rauskäme, wenn
> der auch noch inhaltlich anspruchsvolle Funktionen erfüllen sollte.
Schon mal daran gedacht, daß sich manche Vorteile von mehr Abstraktion 
bei "Blinky"-Äquivalent-Code noch nicht auswirken?

> Und nein, das liegt nicht zwingend an C++ an sich, sondern es zieht
> solche Leute nur verstärkt an. Der Code von Stockfish etwa, einer der
> stärksten Schach-Engines der Welt, ist auch in C++ und sieht trotzdem
> nicht so aus.
Was ein Wunder für ein Stück Code, das 13 Jahre bevor C++17 
verabschiedet wurde, entstand. Immerhin haben sie vereinzelt constexpr 
nachgelegt. Das grundsätzliche Design basiert aber auf C++03.
Warum haben die das eigentlich noch nicht nach Rust portiert, das ist 
doch viel hipper?

von Dr. Sommer (Gast)


Lesenswert?

Weia, was für eine Beitrags-Flut...

Irgendwie nervt mich dieses Standard-Totschlag-Argument "die Kollegen 
müssen das auch verstehen". Wenn man danach geht bleibt man ewig bei 
C90, RCS und 8051 stecken. Das ist wie die sagenumwobene Glass Ceiling, 
man kann sich nicht weiter entwickeln und bleibt immer auf dem selben 
Stand. Irgendwann will man auch einfach mal was neues probieren und 
nicht den 10000. String-Verarbeitungs-Algorithmus in C manuell schreiben 
weil es in C nicht anders geht... Und es kann ja auch nicht sein dass 
der einzige Weg dafür darin besteht zum PowerPoint-Entwickler zu werden. 
Höhere Programmiersprachen wurden ja auch nicht zum Spaß erfunden, C ist 
längst nicht mehr das Maß aller Dinge, da steckt auch viel Potential zur 
Effizienz-Steigerung drin.

Wenn man hier im Forum ein C++ Beispiel zeigt will man zeigen wie es 
auch geht ohne jetzt bei Adam und Eva anfangen und alles erläutern zu 
wollen. Dazu gibt es Bücher und Tutorials. Blöd ist nur wenn es eher 
abschreckend wirkt...

von A. S. (Gast)


Lesenswert?

Heimlehrgangsprogrammierer schrieb:
> Deshalb plädiere ich, C trotzdem noch nicht ganz abzuschreiben.

Oh, das passiert auch nicht. C ist halt viel Handarbeit, was immer dort 
gut ist, wo die vielen hilfreichen aber komplizierten Schablonen anderer 
Sprachkonzepte nicht so ganz passen.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Dr. Sommer schrieb:
> C ist
> längst nicht mehr das Maß aller Dinge,

wie wahr! beispiel, ich portiere gerade einige meiner quellen nach 
micopython und bin beeindruckt von python auf "kleiner" hardware ...


mt

von Oliver S. (oliverso)


Lesenswert?

Frank M. schrieb:
> Peter (peda), der bekanntermaßen schon seit Jahren viele gute
> C-Programme hier im Forum vorstellt und damit auch als C-Experte hier
> bekannt ist,

Bei allem Respekt, PeDa ist auch einer derjenigen, dessen Code schonmal 
unleserlich geschrieben ist, um Zeilen oder auch Zeichen zu sparen. 
Selbsterklärenden Code schreibt der auch nicht immer.

Und natülich treffen mit Peda als HardCore-K&R-C'ler und Wilhelm als 
HardCore C++20'ler völlig verschiedene Welten aufeinander ;)

Oliver

von Nop (Gast)


Lesenswert?

Carl D. schrieb:

> Schon mal daran gedacht, daß sich manche Vorteile von mehr Abstraktion
> bei "Blinky"-Äquivalent-Code noch nicht auswirken?

Sagte ich ja, das wird noch schlimmer, wenn dahinter auch noch Funktion 
steht. Genau das meinte ein gewisser Torvalds, als er bei Git nicht nur 
kein C++ wollte, sondern auch C++-Programmierer draußenhalten. Obwohl 
Git ja nun eindeutig nicht Kernel ist.


Dr. Sommer schrieb:

> Irgendwie nervt mich dieses Standard-Totschlag-Argument "die Kollegen
> müssen das auch verstehen".

Es ist halt nicht nur das reine Programmieren, sondern auch noch 
Domänenwissen, was ebenfalls Jahre braucht. Zuguterletzt will sich auch 
nicht jeder nach einem realen Arbeitstag auch noch in der Freizeit damit 
endlos beschäftigen müssen. C hat den grundlegenden Vorteil, den C++ 
längst verloren hat - es ist eine kompakte Sprache, die man nicht nur in 
der Breite, sondern auch in der Tiefe noch gut überschauen kann.

Aber in der realen Industrie mit Bezug zu embedded ist ja schon C zu 
tricky, daher MISRA-C. Zumal dort auch erheblichenteils nicht 
Informatiker tätig sind, aus guten Gründen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Bei allem Respekt, PeDa ist auch einer derjenigen, dessen Code schonmal
> unleserlich geschrieben ist, um Zeilen oder auch Zeichen zu sparen

Ich denke, das liegt vielmehr daran, dass PeDa in einer Zeit mit C
groß geworden ist, als sein 8051-Compiler noch viel blöder als der
Programmierer war.  Damit hat der Programmierer dann „voroptimiert“.
Mit heutigen Compilern auf heutiger Hardware braucht man sowas nicht
mehr, da kann man eigentlich immer leserlichen Code schreiben.

Die Überschrift des TE war ja auch reichlich unglücklich gewählt: es
kam ihm ja gar nicht darauf an, den Code unleserlich zu machen,
sondern er meinte damit „unorthodox geschrieben“, letztlich aber, um
eine Verbesserung der Lesbarkeit zu erreichen.

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Wenn man hier im Forum ein C++ Beispiel zeigt will man zeigen wie es
> auch geht ohne jetzt bei Adam und Eva anfangen

Das verlangt ja auch keiner.
Nur sollten die Beispiele auch wenigstens compilierbar sein.
Und dazu gehört nunmal, daß man die minimal nötige Compilerversion 
angibt, sowie auch alle benötigten privaten Header postet oder verlinkt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Dr. Sommer schrieb:
>> Wenn man hier im Forum ein C++ Beispiel zeigt will man zeigen wie es
>> auch geht ohne jetzt bei Adam und Eva anfangen
>
> Das verlangt ja auch keiner.
> Nur sollten die Beispiele auch wenigstens compilierbar sein.
> Und dazu gehört nunmal, daß man die minimal nötige Compilerversion
> angibt, sowie auch alle benötigten privaten Header postet oder verlinkt.

Es ergeben sich hier zwei Probleme:

1) Target AVR: es existiert aber keine libstc++ für diese Target. Da 
wird jeder seine eigene haben, oder manche benutzen auch 
https://www.etlcpp.com (die ich selbst nicht verwende, da ich in meiner 
Variante noch Optimierungen vorgenommen habe, manche Teile darf ich 
nicht veröffentlichen, leider kein OSS)

2) In dem oben geposteten Beispiel tauchen Meta-Funktionen aus einer 
(meiner) TMP-Bibliothek auf. Diese kann/darf ich leider nicht öffentlich 
zur Verfügung stellen, auch leider kein OSS.

In Deinem Fall Peter gehe ich davon aus, dass Du als Target AVR hast. 
Hier musst Du also erst mal Problem 1) lösen.

Wenn Du das geschafft hast, bleibt Problem 2). Der Code wird an ein paar 
wenigen Stellen nicht compilieren. Hier kann ich gerne helfen, ohne dass 
ich die ganze TMP-Bibliothek zur Verfügung stellen muss. Dies wäre auch 
gleichzeitig ein guter Einstieg in TMP.

Wobei ich der Meinung bin, dass die Funktion von
1
using x = Meta::pop_front<list>;

klar sein sollte. Wenn man die libstdc++ kennt, hat man mindestens mal 
eine Vermutung, was das macht. Wenn das nicht der Fall ist, musst Du 
Dich zunächst einmal mit TMP beschäftigen. Ansonsten ist der Lerneffekt 
wieder null.

Bottom line: zuerst Problem 1 lösen unabhängig von den hier gezeigten 
Beispielen (oder anderes Target wählen), dann Problem 2 angehen mit 
Wissen über TMP.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Diese kann/darf ich leider nicht öffentlich zur Verfügung stellen, auch
> leider kein OSS.

Dann veröffentliche doch bitte auch keine Beispiele, die darauf
aufsetzen, das hat doch sonst keinerlei Wert für die Community.

Wenn schon, dann liefere halt Rewrites für die entsprechenden Teile.

Dein Problem #1 kann man getrost erstmal zur Seite schieben, solange
sich der Kram dann wenigstens auf dem PC compilieren lässt, denn dann
lässt sich das Beispiel zumindest nachvollziehen.  Selbst für Leute,
die primär sonst auf Controllern arbeiten, schadet es ja nicht, wenn
man irgendeine Demonstration zuerst einmal nur auf dem PC machen
kann.  Ob und wann und unter welchen Umständen man sowas auf eine
Controllerplattform transferieren will, kann dann allemal jeder selbst
entscheiden.

Solange du aber Dinge postest, die ohnehin keiner nachvollziehen kann,
hinterlässt das eben eher den Beigeschmack von Angeberei als den, dass
du anderen Leuten „auf die Sprünge“ helfen möchtest.

von Wilhelm M. (wimalopaan)


Lesenswert?

Jörg W. schrieb:
> Wilhelm M. schrieb:
>> Diese kann/darf ich leider nicht öffentlich zur Verfügung stellen, auch
>> leider kein OSS.
>
> Dann veröffentliche doch bitte auch keine Beispiele, die darauf
> aufsetzen, das hat doch sonst keinerlei Wert für die Community.

Ok, dann lösche bitte alle meine vorigen Beiträge in diesem Thread!

>
> Wenn schon, dann liefere halt Rewrites für die entsprechenden Teile.

Sonst noch Wünsche?

> Solange du aber Dinge postest, die ohnehin keiner nachvollziehen kann,
> hinterlässt das eben eher den Beigeschmack von Angeberei als den, dass
> du anderen Leuten „auf die Sprünge“ helfen möchtest.

Wer Fragen zu TMP hat, soll dann einfach einen neuen Thread aufmachen, 
und ganz groß C++ oben drüber schreiben, damit keine auf die Idee kommt, 
irgendwelchen C oder Basic Code dort zu posten (was mch persönlich nicht 
stören würde).

So, und nun bitte löschen (bis auf diesen hier).

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
>> Wenn schon, dann liefere halt Rewrites für die entsprechenden Teile.
>
> Sonst noch Wünsche?

Alternativ auf eine der 982 OSS-TMP-Libraries umschreiben wie Boost.Hana 
...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Ich bin nicht angetreten, um zu missionieren. Wer das nicht interessant
> findet, soll es halt ignorieren. Die anderen können ja fragen.

Du hattest ja seinerzeit den sehr interessanten und mitunter lehrreichen 
Thread

    Beitrag "Informationen zu C vs C++ / aka Futter für die Diskussion"

gestartet, der auch heute noch regelmäßig neue Beiträge erfährt.

Kannst Du Dir eventuell vorstellen, dass Du dort eine interessiertere 
und kompetentere Leserschaft findest als in solchen Trivial-C-Frage 
Threads wie

    Beitrag "switch(Funktion()) möglich?"

oder

   Beitrag "Code unleserlich schreiben um Zeilen zu sparen." ?

Hier kommt jemand mit einer sehr einfachen Frage zu C, die dem Leser 
direkt offenbart, dass der TO in Sachen C wahrscheinlich nicht nur 
ziemlicher Anfänger ist, sondern gern auch hilfreiche Tipps zu seiner 
Frage von den erfahrenen C-Programmierern wünscht.

Ich kann mir in beiden Fällen leider überhaupt nicht vorstellen, dass 
der jeweilige TO, der sowieso schon mit C seine liebe Müh hat, aufgrund 
Deiner intellektuell sehr anspruchsvollen C++-17-Code-Snippets nun sagen 
wird: "Wilhelm hat Recht! Ich schmeiße C hin, nehme C++-17 und all meine 
Probleme sind gelöst! Alles total easy!"

Ich habe jedenfalls in beiden oben genannten Threads keinerlei Reaktion 
der beiden TOs erkannt - ganz im Gegenteil: Als die Diskussion über die 
C++-Alternativen anfing, haben sich die TOs flugs aus dem Thread 
ausgeklinkt, einfach, weil es sie vermutlich intellektuell in diesem 
Stadium ihres Programmierer-Daseins absolut überforderte.

Das Problem, was ich dann als Moderator sehe: Der Thread driftet 
komplett ab. Das eigentliche Thema tritt dann in den Hintergrund. 
Stattdessen wird der ursprüngliche Trivial-C-Thread mit höchst 
anspruchsvollem C++-17-Code regelrecht geflutet. Diesen Eindruck kann 
man jedenfalls als Leser, den das ursprüngliche C-Thema interessiert, 
durchaus gewinnen. Dieses Vorgehen mag dann in dem einen oder anderen 
Auge des Betrachters gar als Kaperung oder sogar als "Spam" angesehen 
werden.

Deshalb möchte ich Dir folgenden Vorschlag für solche Fälle für die 
Zukunft machen:

Wenn Du für ein Trivial-C-Problem eine elegante C++-17-Lösung siehst, 
die durchaus erwähnenswert ist, verlinkst Du vom Trivial-C-Thread nach

    Beitrag "Informationen zu C vs C++ / aka Futter für die Diskussion"

um dort Deine C++-17-Variante weiterzudiskutieren.

Wäre das ein annehmbarer Vorschlag? In meinen Augen schon, denn dann 
würden solche emotionsgeladenen Reaktionen wie hier erst gar nicht 
auftreten.

P.S.
Ich schreibe oben mit Absicht nicht C++, sondern C++-17, da die hier 
geposteten Code-Snippets allesamt inkompatibel zu älteren bzw. zu den 
meisten auf dem Markt eingeführten C++-Versionen sind.

: Bearbeitet durch Moderator
von A. S. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Ansonsten ist der Lerneffekt wieder null.

Ich finde den Anspruch, das andere vorab was lernen sollen, nicht 
gerechtfertigt. Man sollte doch erst mal sehen, dass ein Problem 
eleganter gelöst ist. Wenn es hingegen komplexer und objektiv schwerer 
lesbar ist, ... wieso dann noch eintauchen? Zumal C++ hier ja meist der 
Optimierung (Speicher und Laufzeit) dient.

Wenn Standard-C++ Standardschablonen für ein Problem hat: Super.

Aber das Argument, dass Du eigene Schablonen für ein Problem hast oder 
erstellen kannst, ... Ich las hier einige Threads (ohne Autoren oder 
Sprachen zu erinnern), wo ein überschaubares Problem "vereinfacht" 
wurde, indem es hinter einer Funktion versteckt wurde, deren 
Implementierung dann dem Leser überlassen hat :-)

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> 2) In dem oben geposteten Beispiel tauchen Meta-Funktionen aus einer
> (meiner) TMP-Bibliothek auf. Diese kann/darf ich leider nicht öffentlich
> zur Verfügung stellen, auch leider kein OSS.

Es wäre schön gewesen, wenn das gleich über den Beispielen gestanden 
hätte.
Gerade einem Anfänger fällt es schwer, zu erkennen, was ist aus 
Standardlibs des Compilers und was nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:

> Deshalb möchte ich Dir folgenden Vorschlag für solche Fälle für die
> Zukunft machen:
>
> Wenn Du für ein Trivial-C-Problem eine elegante C++-17-Lösung siehst,
> die durchaus erwähnenswert ist, verlinkst Du vom Trivial-C-Thread nach
>
>     Beitrag "Informationen zu C vs C++ / aka Futter für die Diskussion"
>
> um dort Deine C++-17-Variante weiterzudiskutieren.

Die Idee, Frank, wird so aber nicht zünden, denn in diesen Thread 
schauen die C Programmierer nicht hinein. Eigentlich war es mein Wunsch, 
in dem o.g. Thread auch nur Verweise auf andere (bessere) Quellen zu 
verlinken. Dort erwähne ich ja auch des öfteren, dass die eigentlichen 
Diskussion besser in anderen, leichter sichtbaren Thread geführt werden 
sollten.

> Wäre das ein annehmbarer Vorschlag? In meinen Augen schon, denn dann
> würden solche emotionsgeladenen Reaktionen wie hier erst gar nicht
> auftreten.

Aber Frank, ich finde es sehr gut, dass Du Dir wirkliche, konstruktive 
Gedanken machst!

Ich stehe zu meiner Grundaussage: "Stop teaching C". Nicht wegen der 
Sprache C im engeren Sinne, sondern weil der Blick für die 
Grundprinzipien des Programmierens verloren geht. Das gilt übrigens auch 
- und das ist die eigentliche Aussage des Spruchs - wenn man mit dem C 
in C++ beginnt.
Wer nicht in größeren Dimensionen denkt, kann an trivialen Beispielen 
den eigentlichen Wert der meisten Beispiele und Umsetzung in 
C++(17/20/..) nicht erkennen.

Bitte nicht falsch verstehen, denn ich bin nicht emotionsgeladen an 
dieser Stelle, aber ich werde in Zukunft immer nachfragen, ob auch 
Interesse an einem Ansatz (in C++) besteht.

Ich möchte jetzt aber dennoch meinem Wunsch nochmals starken Nachdruck 
verleihen, meine Beiträge in diesem Thread zu löschen. Ich weiß, dass 
Euch das Nutzungsrecht gehört, aber ich bitte einfach darum.

von Markus F. (mfro)


Lesenswert?

Wilhelm M. schrieb:
> Ich möchte jetzt aber dennoch meinem Wunsch nochmals starken Nachdruck
> verleihen, meine Beiträge in diesem Thread zu löschen. Ich weiß, dass
> Euch das Nutzungsrecht gehört, aber ich bitte einfach darum.

Vielleicht überlegst Du dir das ja nochmal, wenn Du auch andere Stimmen 
hörst?

Ich persönlich habe überhaupt kein Problem mit diesem Thread. Im 
Gegenteil, ich hab' ihn genossen.

Der TO hat schon sehr früh erschöpfend Auskuft bekommen. Wahrscheinlich 
mehr als er eigentlich wissen wollte. So what? Ab da kann man sich 
anderen Dingen widmen.

Auch wenn ich persönlich nicht alles gut und richtig finde, was an 
"neuem" C++ so kommt, selbst hauptsächlich in C programmiere (und daran 
in absehbarer Zeit wahrscheinlich auch nichts ändern werde), finde ich 
doch alles, was man "dazulernen" kann, gut und richtig. Ich muss es ja 
nicht verwenden, wenn ich  (für mich) das Gefühl habe, das es nicht 
passt. Wem's gar nicht passt, der muss es nicht mal lesen.

Wenn dieses (Diskussions-) Forum nur noch Beiträge toleriert, die 100%ig 
auf die gestellte Frage eingehen, verliert es (für mich) gewaltig an 
Wert. Meist entstehen die wirklich interessanten Fragen und Antworten 
gerade erst aus der Diskussion.

"Rummäkler" mäkeln meiner Ansicht nach oft genug lediglich aus 
verletzter Eitelkeit mit Neid ("der kann was, was ich nicht mal 
verstehe, das muss also akademischer Mist sein").

Da solltest Du drüber stehen. Kompetenz klingt halt nun manchmal 
arrogant ... ;)

: Bearbeitet durch User
Beitrag #5446046 wurde vom Autor gelöscht.
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Markus F. schrieb:
> Wenn dieses (Diskussions-) Forum nur noch Beiträge toleriert, die 100%ig
> auf die gestellte Frage eingehen, verliert es (für mich) gewaltig an
> Wert. Meist entstehen die wirklich interessanten Fragen und Antworten
> gerade erst aus der Diskussion.
>
> "Rummäkler" mäkeln meiner Ansicht nach oft genug lediglich aus
> verletzter Eitelkeit mit Neid ("der kann was, was ich nicht mal
> verstehe, das muss also akademischer Mist sein").
>
> Da solltest Du drüber stehen. Kompetenz klingt halt nun manchmal
> arrogant ... ;)

da bin ich voll dabei!
ich lese alles zu c++ und archiviere sogar die beipiele, die ich heute 
zugegebenerweise absolut nicht verstehe, aber irgendwann mal 
nachvollziehen möchte.

was mich richtig stört, ist die nivellierung nach unten und nicht die 
vereinzelten "leuchtenen blüten"! ich würde gerne sehen, dass das forum 
einen einsteiger- UND "experten" -bereich schaft.

also hört bitte auf damit, das niveau immer weiter nach unten zu 
drücken, z.b. mit der begründung das jeder es verstehen soll.

ich denke, dass der niveauverfall in der gesellschft gewünscht und 
gefördert wird. aber ich wehre mich dagegen - soll heisen was/wer 
schrott/doof ist wird auch so benannt und nicht immer nur schön reden.


mt

von Nop (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Die Idee, Frank, wird so aber nicht zünden, denn in diesen Thread
> schauen die C Programmierer nicht hinein.

Richtig. Vielleicht wäre es auch eine Idee, C-Programmierern nicht 
permanent mit C++ auf den Senkel zu gehen. Dieses Missionieren ist 
einfach nur lästig.

> aber ich werde in Zukunft immer nachfragen, ob auch
> Interesse an einem Ansatz (in C++) besteht.

Ich fände es schön, wenn Du das in C-Threads einfach seinläßt. Du 
fändest es umgedreht auch störend, wenn Du über C++ reden willst und 
dann C-Programmierer stattdessen darüber diskutieren, daß das 
schlichtweg Obfuscation ist.

von Nop (Gast)


Lesenswert?

Frank M. schrieb:

> Ich kann mir in beiden Fällen leider überhaupt nicht vorstellen, dass
> der jeweilige TO, der sowieso schon mit C seine liebe Müh hat, aufgrund
> Deiner intellektuell sehr anspruchsvollen C++-17-Code-Snippets nun sagen
> wird: "Wilhelm hat Recht! Ich schmeiße C hin, nehme C++-17 und all meine
> Probleme sind gelöst! Alles total easy!"

Eines habe ich übrigens durchaus daraus gelernt, nämlich was offenbar 
der Hintergrund war, wieso Torvalds in seinem bekannten Rant zum Thema 
"Git in C?" schrieb "even if the choice of C were to do nothing but 
keep the C++ programmers out, that in itself would be a huge reason to 
use C."

Nunja, einfach damit das Projekt eben nicht mit solchem Code endet wie 
demonstriert.

von mh (Gast)


Lesenswert?

Nop schrieb:
> Ich fände es schön, wenn Du das in C-Threads einfach seinläßt. Du
> fändest es umgedreht auch störend, wenn Du über C++ reden willst und
> dann C-Programmierer stattdessen darüber diskutieren, daß das
> schlichtweg Obfuscation ist.

Hier besteht ein logisches Problem:
Du willst die C++ Beiträge nicht sehen, deswegen sollen sie nicht 
geschrieben werden. Andere Teilnehmer wollen die Beiträge aber lesen 
(und zwar in genau dem Zusammenhang, in dem sie jetzt stehen).
Lösung:
Die Beiträge werden weiterhin geschrieben und DU (und alle die ebenfalls 
nicht interessiert sind) ignorierst sie.

von Nop (Gast)


Lesenswert?

mh schrieb:

> Lösung:
> Die Beiträge werden weiterhin geschrieben und DU (und alle die ebenfalls
> nicht interessiert sind) ignorierst sie.

Schön, dann kann man auch jeden Thread mit anderem peripher 
interessantem Offtopic zumüllen. Kann man ja überlesen, oder?

von mh (Gast)


Lesenswert?

Nop schrieb:
> Schön, dann kann man auch jeden Thread mit anderem peripher
> interessantem Offtopic zumüllen. Kann man ja überlesen, oder?

Ich sehe kein Problem wenn sich die Diskussion in eine andere Richtung 
bewegt, wenn genügend Teilnehmer daran interessiert sind.

Und C++ Alternativen zu C Beispielen sind nun wirklich kein Offtopic in 
einem Thread der sich "Code unleserlich schreiben um Zeilen zu sparen" 
nennt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

mh schrieb:
> Und C++ Alternativen zu C Beispielen sind nun wirklich kein Offtopic in
> einem Thread der sich "Code unleserlich schreiben um Zeilen zu sparen"
> nennt.

Wobei danach das „unleserlich“ vom TE korrigiert worden ist: es sollte
durchaus besser lesbar werden, so die Intention.  Dahingehend ist
manches der C++-Beispiele durchaus nicht gerade on-topic :), auch wenn
es vielleicht mehr „Coolheitsfaktor“ hat oder halt auch Arbeit spart,
wenn sich am Algorithmus zur Generierung der Daten mal was ändert
(wofür man im Original hätte die komplette Tabelle händisch neu
tippen müssen).

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> wenn sich am Algorithmus zur Generierung der Daten mal was ändert

Sowas ist z.B. praktisch für CRC-Tabellen (mit welchen man den 
CRC-Algorithmus stark beschleunigen kann); die kann man per 
constexpr-Algorithmus generieren und so spart man sich endlose 
Zahlenfolgen im Code. Wenn man einen Parameter zur Erzeugung ändern will 
kann man das im Code schnell abändern und muss keine externen Tools 
anwerfen. Leider gibt's ja Protokolle die so vermurkste 
Nicht-Standard-CRC's nutzen die man nicht mit den CRC-Hardwareeinheiten 
von Mikrocontrollern erzeugen kann, wie z.B. beim LTC6804.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
>> wenn sich am Algorithmus zur Generierung der Daten mal was ändert
>
> Sowas ist z.B. praktisch für CRC-Tabellen (mit welchen man den
> CRC-Algorithmus stark beschleunigen kann)

Nur: gerade diese legt man in der Regel genau einmal an, danach
sollten sie sich nicht mehr ändern. :)

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> Nur: gerade diese legt man in der Regel genau einmal an, danach
> sollten sie sich nicht mehr ändern. :)

Na, sobald man einen anderen Kommunikationspartner mit anderen 
Sonderwünschen an die CRC hat muss man sie neu anlegen...

von Markus F. (mfro)


Lesenswert?

Jörg W. schrieb:
> mh schrieb:
>> Und C++ Alternativen zu C Beispielen sind nun wirklich kein Offtopic in
>> einem Thread der sich "Code unleserlich schreiben um Zeilen zu sparen"
>> nennt.
>
> Wobei danach das „unleserlich“ vom TE korrigiert worden ist: es sollte
> durchaus besser lesbar werden, so die Intention.  Dahingehend ist
> manches der C++-Beispiele durchaus nicht gerade on-topic :),

Nun ja, in einem Thread, wo das Topic erst x ist und anschließend !x, 
ist es per se ein wenig schwierig, on-topic zu bleiben, nicht wahr?

von Gerhard O. (gerhard_)


Lesenswert?

Also mir ist das Beispiel Programm von Wilhelm "unheimlich". Wenn man da 
nicht wirklich ein solide C++ Grundlage, Verständnis und 
Erinnerungsvermögen an die Sprachelemente und Beziehungen hat, ist es 
dem Uneingeweihten praktisch unmöglich das Programm funktionell im 
Detail zu untersuchen. Beim alten C ist praktisch alles offen und man 
kann ein Programm sehr gut analysieren. Beim obigen Beispiel ist alles 
hinter den Regeln und Sprachen Design Details versteckt. Als C++ 
Anfänger tut man sich dann richtig schwer die pertinenten Daten Details 
und Zusammenhänge zu verstehen und verfolgen. Die "Aha" Momente muss man 
sich als Laie hier schwer erarbeiten und kommen leider nur recht selten.

Wer da professionell tagtäglich mit dem neuesten C++ arbeitet, womöglich 
noch einige Universitätskurse abgelegt hat, für den ist das natürlich 
alltäglich und in Fleisch und Blut übergegangen. Also seid geduldig mit 
dem Rest der Welt der diesen tiefen Einblick in die neuen 
Sprachentwicklungen nicht immer hat. Was Euch selbstverständlich ist, 
ist für den Rest der Welt oft nur noch "Bahnhof".

OK. Und jetzt trampelt bitte nicht zu sehr auf mich herum. Ich fand 
diese Erörterungen durchaus sehr interessant. Aber im Augenblick muss 
ich einen sehr großen Bogen um die Materie machen:-)


Schönen Tag noch,
Gerhard

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Nun ja, in einem Thread, wo das Topic erst x ist und anschließend !x

War es ja nicht wirklich, und wer die Beiträge des TE aufmerksam
gelesen hatte, dem wurde das schnell klar.

Seine Überschrift war halt nur arg ungeschickt ausgedrückt.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

Vielleicht noch zwei Sachen zu der ganzen Thematik und Aufregung hier:

In dem Beitrag

Beitrag "Re: Code unleserlich schreiben um Zeilen zu sparen."

hatte ich vollständigen und funktionierenden Code gepostet, mit einer 
kleinen Ausnahme, die ich dort auch beschrieben hatte: und zwar 
Util::sort() aus dem Include-File "util/algorithm.h". Dazu hatte ich 
geschrieben, dass es ein constexpr Bubble-Sort sein dürfte.

Meine Schlußfolgerung daraus war / ist: es hat niemand, der sich hier 
beschwert hat, jemals ausprobiert, den Code in einer C++17 Umgebung zu 
kompilieren. Hätte das jemand versucht, dann wäre es ihm wie beschrieben 
ausgefallen und er hätte es lediglich auskommentieren müssen. Den die 
Eingangsdaten des Algorithmus waren bereits sortiert. Oder eben ein 
Bubble programmieren. Hey Leute, das war doch machbar oder?

Zum anderen warte ich auch eine Antwort eines der hier mitlesenden / 
mitpostenden Moderatoren zu meinem nachdrücklichen Wunsch, meine 
Beiträge hier zu löschen. Da ist leider nichts erfolgt.

von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> Meine Schlußfolgerung daraus war / ist: es hat niemand, der sich hier
> beschwert hat, jemals ausprobiert, den Code in einer C++17 Umgebung zu
> kompilieren. Hätte das jemand versucht, dann wäre es ihm wie beschrieben
> ausgefallen und er hätte es lediglich auskommentieren müssen.

Ich habe mal nachgesehen welche GNU Version für Windows erhältlich ist 
und wenn ich es nicht falsch interpretiert habe, ist V5.1 die neueste 
Version die allerdings bis C++14 unterstützt. V8 mit C++17 scheint es im 
Augenblick nur für Linux zu geben. Wie gesagt ich kenne mich mit den 
erhältlichen Versionen nicht so aus. V4.92 ist die neueste Version die 
ich im Betrieb habe.

https://sourceforge.net/projects/tdm-gcc/files/latest/download

Gibt es eine C++17 Windows Version und kann man sich eine Windows 
kompatible C++17 installieren?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

MinGW / CygWin hat gcc-8.1 (C++2a)

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> MinGW / CygWin hat gcc-8.1 (C++2a)

Danke!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Zum anderen warte ich auch eine Antwort eines der hier mitlesenden /
> mitpostenden Moderatoren zu meinem nachdrücklichen Wunsch, meine
> Beiträge hier zu löschen.

Finde zumindest ich unpassend.  Dann müsste man einen ziemlich großen
Teil der Diskussion, die sich rundherum entsponnen hat, löschen, denn
die hat losgelöst keinen Sinn.  Deine Beiträge verstoßen ja auch nicht
gegen die Nutzungsbestimmungen, sie sind eben (m. E.) nur nicht so
hilfreich, wie sie sein könnten, wenn sie auch jeder compilieren
kann (ok, jeder, den es interessiert).

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:
> Wilhelm M. schrieb:
>> MinGW / CygWin hat gcc-8.1 (C++2a)
>
> Danke!

Bei Cygwin ist es doch nur 7.3, sorry! Aber das sollte auch reichen.

Ansonsten: VM / ArchLinux

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> Bei Cyg

Wilhelm M. schrieb:
> Gerhard O. schrieb:
>> Wilhelm M. schrieb:
>>> MinGW / CygWin hat gcc-8.1 (C++2a)
>>
>> Danke!
>
> Bei Cygwin ist es doch nur 7.3, sorry! Aber das sollte auch reichen.
>
> Ansonsten: VM / ArchLinux

OK. Danke für die Berichtigung.

von Possetitjel (Gast)


Lesenswert?

Markus F. schrieb:

> "Rummäkler" mäkeln meiner Ansicht nach oft genug
> lediglich aus verletzter Eitelkeit mit Neid ("der
> kann was, was ich nicht mal verstehe, das muss
> also akademischer Mist sein").

Die Unverständlichkeit vieler Computerthemen ist
meiner Erfahrung nach nicht ihrer tatsächlichen
Kompliziertheit geschuldet, sondern der Unfähigkeit
bzw. der Unlust der Missionare, sich allgemein-
verständlich auszudrücken.

Die Geschichte der Informatik ist die Geschichte
schlechter Begriffsbildungen und hirnrissiger
Erklärungen.

Wenn ich Potenzial hinter einem Konzept erkenne, bin
ich durchaus lernwillig. Ich bin aber nicht bereit,
als Initiationsritus unter Schmerzen irgend einen
Gehirnkrampf auswendig zu lernen, nur um dazuzugehören.

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Carl D. schrieb:
>
>> Schon mal daran gedacht, daß sich manche Vorteile von mehr Abstraktion
>> bei "Blinky"-Äquivalent-Code noch nicht auswirken?
>
> Sagte ich ja, das wird noch schlimmer, wenn dahinter auch noch Funktion
> steht.
Das Prinzip von unterschiedlichen fixen und variablen Kosten und der 
Punkt (meist etwas oberhalb von trivial) an dem "wenig fix/viel 
variabel" Dei Variante "viel fix/wenig variabel" kostenmäßig überholt, 
sollte auch nicht-BWLern geläufig sein. Naja, vielleicht auch nicht, 
wenn nicht mal mein einfacher Satz für jeden sinnbegreifend lesbar ist.

> Genau das meinte ein gewisser Torvalds, als er bei Git nicht nur
> kein C++ wollte, sondern auch C++-Programmierer draußenhalten. Obwohl
> Git ja nun eindeutig nicht Kernel ist.
Wenn es um Linux (und auch GIT) geht, mag man ihn für einen Gott halten, 
er ist aber sicher nicht unfehlbar.

von Carl D. (jcw2)


Lesenswert?

Jörg W. schrieb:
> Dr. Sommer schrieb:
>>> wenn sich am Algorithmus zur Generierung der Daten mal was ändert
>>
>> Sowas ist z.B. praktisch für CRC-Tabellen (mit welchen man den
>> CRC-Algorithmus stark beschleunigen kann)
>
> Nur: gerade diese legt man in der Regel genau einmal an, danach
> sollten sie sich nicht mehr ändern. :)

Wenn man aber den Rechenweg hinschreibt, dann ist man einen Level 
weiter.
Es gibt z.B. 1Wire-Slave Implementierungen für AVR, da steht dann:
"wenn die ID geändert wird, bitte online via <link> den neuen CRC-Wert 
berechnen. Oder es steht ein constexpr constructor eine OneWireId Klasse 
da, der die CRC-Berechnung zur Compilezeit macht.
Das ist nur ein kleines Beispiel.

Man kann z.B. auf STM32 4 Bits eines LCD-Daten-"Worts" beliebig auf 
einem 16bit-Port anordnen und zur Compile-Time eine LUT mit 16 Werten 
für das BSRR (Bit Set/Reset Register) erzeugen, die dann per "echten 
Wert" indiziert, die passenden Pins befüllt. Wohlgemerkt beliebige 
Verteilung der Pins innerhalb des Ports.

Bei jedem dieser Beispiele bekommt man dann von "mitfiebernde" 
anerkennende Wort, von den anderen die Ausrede, das geht doch in xyz so 
und muß nicht anders sein.
Wenn es so wäre, daß nicht die Summe der komplizierten Detail unser 
Rechenspielzeuge ausmachen würde, dann wäre ein Abakus immer die beste 
Lösung.

von Carl D. (jcw2)


Lesenswert?

Possetitjel schrieb:
> Markus F. schrieb:
>
>> "Rummäkler" mäkeln meiner Ansicht nach oft genug
>> lediglich aus verletzter Eitelkeit mit Neid ("der
>> kann was, was ich nicht mal verstehe, das muss
>> also akademischer Mist sein").
>
> Die Unverständlichkeit vieler Computerthemen ist
> meiner Erfahrung nach nicht ihrer tatsächlichen
> Kompliziertheit geschuldet, sondern der Unfähigkeit
> bzw. der Unlust der Missionare, sich allgemein-
> verständlich auszudrücken.
In seltene Fällen aber auch am Unvermögen bzw der Unlust der 
Missionierten, sich auf neues einzulassen.

> Die Geschichte der Informatik ist die Geschichte
> schlechter Begriffsbildungen und hirnrissiger
> Erklärungen.
Die ganze Geschichte von Wissenschaft und Technik zeigt, daß es auch mal 
ein/zwei Generationen Dauern kann, bis Spezialwissen zum Allgemeingut 
wird. Im Mittelalter wäre man für das Verbreiten von C++-Knowhow 
verbrannt worden.

> Wenn ich Potenzial hinter einem Konzept erkenne, bin
> ich durchaus lernwillig. Ich bin aber nicht bereit,
> als Initiationsritus unter Schmerzen irgend einen
> Gehirnkrampf auswendig zu lernen, nur um dazuzugehören.
Manchmal kann der Erkenntnisstand der "Pioniere" aber nicht auf 
Nachzügler warten.

von Veit D. (devil-elec)


Lesenswert?


von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> avr-gcc Pakete für Windows:
>
> 
https://sourceforge.net/projects/mobilechessboar/files/avr-gcc%20snapshots%20%28Win32%29/
>
> http://blog.zakkemble.co.uk/avr-gcc-builds/

Und nochmal: avr-gcc ist keine(!) vollständige C++ Umgebung: es fehlt 
die libstdc++. Habe ich oben alles geschrieben. Bitte lesen!

Den meisten Leuten hier nutzt das also nichts, um das o.g. Beispiel zu 
compilieren. Es geht nur mit einer vollständigen C++ Umgebung, etwa auf 
dem PC.

von Wilhelm M. (wimalopaan)


Lesenswert?

Possetitjel schrieb:
> Markus F. schrieb:
>
>> "Rummäkler" mäkeln meiner Ansicht nach oft genug
>> lediglich aus verletzter Eitelkeit mit Neid ("der
>> kann was, was ich nicht mal verstehe, das muss
>> also akademischer Mist sein").
>
> Die Unverständlichkeit vieler Computerthemen ist
> meiner Erfahrung nach nicht ihrer tatsächlichen
> Kompliziertheit geschuldet, sondern der Unfähigkeit
> bzw. der Unlust der Missionare, sich allgemein-
> verständlich auszudrücken.

Jede Fachdisziplin hat ihr eigenes Idiom. Die Mediziner sind da ganz 
weit "vorn", indem sie ihre Idiome in Latein/Griechisch ausdrücken. Dei 
den Informatikern ist es überwiegend Englisch, wenn man "pipe" nicht mit 
"Rohr" zwanghaft ins Deutsche übersetzen will.

Wir reden von Klassen, Funktionen, Elementfunktionen, Methode, 
Nachricht, Datentypen, abstrakte Datentypen, generische Datentypen, 
Objekten, Instanzen, Exemplaren und alles hat eine ziemlich festgelegte 
Bedeutung. Je nach Kontext kann die eine oder andere Ausprägung eines 
Begriffes im Vordergrund stehen.

Im allgemeinen ist es verständlicher, sich in dem zur Fachdisziplin 
gehörenden Idiom auszudrücken, weil es prägnanten ist und man deswegen 
weniger umschreiben muss: man sagt einfach "FiFo" oder "FiFo-ordered 
Queue" statt: die Datenstruktur, die zwei (mindestens) Operationen 
anbietet; eine, um Elemente anzufügen und eine, um Elemente zu 
entfernen.


> Die Geschichte der Informatik ist die Geschichte
> schlechter Begriffsbildungen und hirnrissiger
> Erklärungen.

Beispiele?

von Nop (Gast)


Lesenswert?

Carl D. schrieb:

> Das Prinzip von unterschiedlichen fixen und variablen Kosten und der
> Punkt (meist etwas oberhalb von trivial) an dem "wenig fix/viel
> variabel" Dei Variante "viel fix/wenig variabel" kostenmäßig überholt,
> sollte auch nicht-BWLern geläufig sein.

Mag sein, daß man für größere Projekte tatsächlich C++ braucht. Aber 
kleinere Projekte wie etwa der Linuxkernel mit 25 Millionen Codezeilen 
gehen auch ganz gut in C, dann hat man auch nicht den ganzen Quatsch von 
C++.

von Possetitjel (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Possetitjel schrieb:
>> Markus F. schrieb:
>>
>>> "Rummäkler" mäkeln meiner Ansicht nach oft genug
>>> lediglich aus verletzter Eitelkeit mit Neid ("der
>>> kann was, was ich nicht mal verstehe, das muss
>>> also akademischer Mist sein").
>>
>> Die Unverständlichkeit vieler Computerthemen ist
>> meiner Erfahrung nach nicht ihrer tatsächlichen
>> Kompliziertheit geschuldet, sondern der Unfähigkeit
>> bzw. der Unlust der Missionare, sich allgemein-
>> verständlich auszudrücken.
>
> Jede Fachdisziplin hat ihr eigenes Idiom.

Klar. Präzise Fachsprache ist wichtig und sinnvoll.


> Die Mediziner sind da ganz weit "vorn", indem sie ihre
> Idiome in Latein/Griechisch ausdrücken.

Sehr gutes Beispiel: In der Medizin kann man am lebenden
Objekt studieren, wie man Sprache als Waffe verwendet, um
sich abzugrenzen und anderen auszuschließen.
(Soweit ich weiss, war das Ziel, vom Status des Jahrmarkts-
gauklers wegzukommen und sich äußerlich sichtbar der
Gelehrtenwelt anzugliedern, ein wesentlicher Grund dafür,
dass Chirurgen und ähnliche Leute begonnen haben, Lateinisch
zu reden. Es ging dabei nicht nur um Fachsprache, sondern
sehr wesentlich auch um sozialen Status. Und das hat, wie
man an den "Göttern in Weiss" sieht, auch funktioniert.)


> Dei den Informatikern ist es überwiegend Englisch, wenn
> man "pipe" nicht mit "Rohr" zwanghaft ins Deutsche
> übersetzen will.

Ich habe mit dem Englischen als "lingua franca" der modernen
Technik meinen Frieden gemacht. Das ist nicht mein Punkt.


> Wir reden von Klassen, Funktionen, [...]

Dazu unten mehr.


>> Die Geschichte der Informatik ist die Geschichte
>> schlechter Begriffsbildungen und hirnrissiger
>> Erklärungen.
>
> Beispiele?

Unzählige.

Wenn man als Einstieg mal bei Wikipädie "Programmierparadigma"
nachschlägt, dann findet man einen Berg von Geschwurbel vor,
der eines schlechten literaturwissenschaftlichen Seminars
würdig wäre. Das liegt aber nicht daran, dass die WP-Autoren
dumm wären, sondern daran, dass sich auch außerhalb der
Wikipädie niemand die Mühe gemacht hat, das hinterliegende
Konzept klar und deutlich herauszuarbeiten.

Und das Konzept ist: Programme beschreiben Automaten.

In der klassischen Ära (FORTRAN) beschrieb das Programm im
Wesentlichen einen großen Automaten; die Steuerstruktur
bestand aus GOTO, und die Variablen waren global.

Die strukturierte Programmierung ging auf die Kombinatorik
des Automaten los und legte Regeln zu dessen Strukturierung
fest; als Ergebnis dessen liegen (in Form der Prozeduren und
Funktionen) viele kleine kombinatorische Schaltnetzwerke mit
klar definierten Schnittstellen vor, die (durch Aufruf) zur
Laufzeit miteinander verschaltet werden können.

Der nächste (offensichtliche) Schritt ist die modulare
Programmierung; sie überträgt den Gedanken der Zerlegung in
handliche Teile von der Kombinatorik des Automaten auf die
Flipflop-Batterie und bildet, indem sie Flipflops und
Kombinatorik gemeinsam KAPSELT, erstmals echte Teilautomaten.

Die objektorientierte Programmierung geht hier insofern noch
einen Schritt weiter, als dass sie es erstmals ermöglicht,
zur Programmlaufzeit eine erst zur Laufzeit wählbare Anzahl
an Exemplaren desselben Automatentyps zu erzeugen. In dieser
Sichtweise ist weder die Vererbung noch die Kapselung eine
echte artbildende Eigenheit der OOP, sondern die Tatsache,
dass man Objekte zur Laufzeit erzeugen und vernichten kann.

Objekte als gekapselte Zusammenfassung von Daten und Code
sind also schlicht und ergreifend Automaten (die ja aus
einer Kombinatorik und einer Flipflop-Batterie bestehen),
und ein objektorientiertes Programm beschreibt ein Automaten-
netz.

Das Riesentamtam, das um die Detail der Vererbung (Mehrfach-
vererbung, Diamond-Problem) gemacht wird, ist in dieser Sicht
ein aufgebauschtes bürokratisches, verwaltungstechnisches
Problem, das man auch entsprechend behandeln sollte. OOP
geht auch ohne Vererbung -- also sind Vererbungsprobleme
keine immanenten OOP-Probleme.

Die Modellvorstellung "Programme beschreiben Automatennetze"
hat noch einen anderen Vorteil.

Als ich mich vor Jahren mit einem Kollegen, der im Gegensatz
zu mir einschlägige Vorlesungen gehört hatte, über VHDL
unterhielt, sagte dieser einen geradezu prophetischen Satz:
"Ach weisst Du, das ist im Prinzip genau wie C... nur es
passiert eben alles gleichzeitig."

Die Vorstellung "Programme beschreiben Automatennetze"
hat den großen Vorzug, dass sie von der (längst nicht
mehr gültigen) technischen Zufälligkeit einer sequenziellen
Maschine abstrahiert. Dabei gibt es zwei praktisch wichtige
Entwicklungsrichtungen:
Zum einen ist da das Multitasking, dessen Kern ja darin liegt,
das zahlreiche unabhängige ("virtuelle") Automaten auf dieselbe
Hardware abgebildet werden und gleichzeitig ohne sich zu stören
arbeiten. Extremstes Beispiel ist die SPS, die perfektes
Multitasking bietet, ohne den Begriff überhaupt zu kennen.
(Wer mal bei der Inbetriebnahme einer Rundtischmaschine mit
16 Stationen und hunderten Aktoren dabeiwar, weiss, was ich
meine. Wenn es hierbei einen "Crash" gibt, dann gibt es WIRKLICH
einen Crash.)
Zum anderen ist auch der Prozessor selbst längst keine rein
sequenzielle Maschine mehr; man hält lediglich an diesem
Programmiermodell fest, weil man noch kein besseres hat, das
für den Masseneinsatz tauglich wäre. Tatsächlich macht ein
üblicher PC-Prozessor ja vieles parallel, was im Programm
m.o.w. sequenziell beschrieben ist. Wenn man diese Gedanken-
schiene weiterfährt, landet man bei VHDL.

Zwei abschließende Gedanken zu diesem Teilast. Erstens: Mir
ist inzwischen klar, dass man Berechenbarkeit nicht nur mit
Bezug auf den Turing-Automaten als Modellmaschine erklären
kann, sondern auch über den Lambda-Kalkül. Wie die Brücke
von der Automatentheorie zum Lambda-Kalkül aussieht, ist mir
noch nicht klar. Lisp/Scheme/Tcl sind aber der Beweis dafür,
dass diese Frage praktisch relevant ist.
Zweitens: Auch die Brücke vom "Standard-Modell der Informatik"
(der Turing-Maschine, die ja sequenziell arbeitet) zur von
mir ständig zitierten Automatentheorie ist u.U. nicht auf
den ersten Blick offensichtlich. Man kann sich aber leicht
vorstellen, dass die Automaten durch boolesche Gleichungen
beschrieben werden können, welche wiederum durch die Turing-
Maschine sequenziell ausgewertet werden. Das führt auf das
interessante Thema, dass durch fehlerhafte Auswertung an sich
korrekter Gleichungen "parasitäre" Zustände entstehen, die
z.B. zu unerwünschten Blockierungen führen (Stichwort
"Warteschleifen und Nebenläufigkeit").

So. - Du schreibst oben, man spräche von Klassen, Methoden,
Elementfunktionen und so weiter.
Richtig. Um meine Kritik aggressiv zu formulieren: Die
praktischen Informatiker führen sich wie die spanischen
Eroberer oder die amerikanischen Siedler auf, die irgendwo
einfallen, alles niederbrennen, ihr eigenes Getreide säen
und sich einen feuchten Kehricht dafür interessieren, was
lange vor ihrem Einfallen dort schon an Interessantem
gewachsen ist.

Eine "Funktion" (im Sinne der Informatik) ist einfach eine
Kombinatorik (kombinatorischer Automat).
Ein "Objekt" ist ein Automat.
Eine "member function" ist eine zu einem Automaten gehörende
Kombinatorik.
Eine "Klasse" ist der Schaltplan eines (abstrakten) Automaten.
Eine "Instanz" ist ein konkretes Exemplar eines abstrakten
Automaten, das nach dem gültigen Schaltplan hergestellt wurde.

Nach meiner Wahrnehmung werden Sprachkonstrukte immer nur mit
Verweis auf die Theorie der Programmiersprachen erklärt. Das
kommt den Informatikern offenbar völlig natürlich vor, ist aber
deshalb fatal, weil die Programmiersprachen selbst auch nur ein
HILFSMITTEL sind -- sie dienen nämlich dazu, das VERHALTEN VON
AUTOMATEN zu beschreiben!
Die Informatiker sollten also diesen inzestuösen Rahmen, in
dem Sprachkonstrukte immer nur durch Begriffe aus der Theorie
der Programmiersprachen beschrieben werden, endlich mal ver-
lassen, und sich auf die viel relevantere Frage konzentrieren,
welchen neuen AUTOMATENSTRUKTUREN ich mit diesen Sprach-
konstrukten beschreiben kann, und warum das nützlich ist.

von Possetitjel (Gast)


Lesenswert?

Carl D. schrieb:

> Manchmal kann der Erkenntnisstand der "Pioniere" aber
> nicht auf Nachzügler warten.

Es geht nicht um den Erkenntnisstand an sich, sondern
um die Unfähigkeit oder die Unlust, die unter vielen
persönlichen Mühen gewonnenen Erkenntnisse so umzuformu-
lieren, dass sie für andere leicht verständlich werden.

Edison sage, Genie sei 1% Inspiration und 99% Transpiration.

Die geniale Erkenntnis zu haben ist 1%, sie verständlich
zu formulieren und lehrbar zu machen, die restlichen 99%.

von Roland F. (rhf)


Lesenswert?

Hallo,

Possetitjel schrieb:
> Die Informatiker sollten also diesen inzestuösen Rahmen, in
> dem Sprachkonstrukte immer nur durch Begriffe aus der Theorie
> der Programmiersprachen beschrieben werden, endlich mal ver-
> lassen, und sich auf die viel relevantere Frage konzentrieren,
> welchen neuen AUTOMATENSTRUKTUREN ich mit diesen Sprach-
> konstrukten beschreiben kann, und warum das nützlich ist.

Du hast es perfekt zusammengefasst.
Das trifft allerdings nicht nur auf die "Programmierspracheninformatik" 
zu, sondern findet sich immer mehr in anderen technischen Bereichen 
wieder.

rhf

von Wilhelm M. (wimalopaan)


Lesenswert?

Possetitjel schrieb:

Frei nach dem Motto: ich schreibe eine lange Antwort, weil keine Zeit 
hatte, mich kurz zu fassen.

> Und das Konzept ist: Programme beschreiben Automaten.

Nun, das lernen Informatiker typischerweise am ersten Tag.

> Nach meiner Wahrnehmung werden Sprachkonstrukte immer nur mit
> Verweis auf die Theorie der Programmiersprachen erklärt. Das
> kommt den Informatikern offenbar völlig natürlich vor, ist aber
> deshalb fatal, weil die Programmiersprachen selbst auch nur ein
> HILFSMITTEL sind -- sie dienen nämlich dazu, das VERHALTEN VON
> AUTOMATEN zu beschreiben!

s.o.

von Possetitjel (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Possetitjel schrieb:
>
> Frei nach dem Motto: ich schreibe eine lange Antwort,
> weil keine Zeit hatte, mich kurz zu fassen.

Du irrst -- das IST die Kurzfassung.

Sie ist so lang geworden, weil ich den roten Faden klar
darstellen wollte.


>> Und das Konzept ist: Programme beschreiben Automaten.
>
> Nun, das lernen Informatiker typischerweise am ersten
> Tag.

Mag wohl sein, dass sie es lernen -- aber sie begreifen
es nicht.


Sie lernen, dass es eine Korrespondenz zwischen den
Chomsky-Grammatiken und bestimmten Automatenklassen gibt.
Soweit stimmt das.

Die logische Umkehrung dieses Gedankens, dass ein Satz in
einer gegebenen Chomsky-Grammatik (vulgo: ein Programm)
dann auch genau einen bestimmten Automaten beschreiben
muss, habe ich noch NIRGENDWO gelesen. Nirgends. Das ist
den akademischen Theoretikern viel zu trivial, als dass
man es aufschreiben dürfte.

Selbstverständlich ist diese Umkehrung aus theoretischer
Sicht trivial -- sie ist aber aus praktischer Sicht
entscheidend, weil sie die Grundlage für meine anschauliche
Vorstellung ist: Ich darf mir JEDES Programm als Zusammen-
schaltung von 74HCxx-ICs vorstellen. Es ist mathematisch
beweisbar, dass diese Deutung zulässig ist!


Du hast Dich oben beklagt, dass Deine Versuche, C++ und
seine Vorteile zu popularisieren, so stark auf Ablehnung
stoßen. Ich habe versucht, die Ursache für diese Ablehnung
zu ergründen, indem ich meine eigenen Gedanken und Eindrücke
niederschreibe.
Etwas kürzer als oben würde ich so sagen:

Du zitierst (aus meiner Sicht zu Recht) die Forderung "stop
teaching C". Du wirst ihr aber nicht gerecht, denn Du lehrst
C++ genau so, wie all die furchtbaren C-Lehrbücher C lehren!
Du springst -- genau wie die Lehrbücher -- kopfüber in die
Details der Sprache, die festlegen, WIE man Sachverhalte
formuliert, statt Dich erstmal ausführlich bei dem (für Dich
entsetzlich langweiligen und trivialen) Thema aufzuhalten,
WAS man in der Sprache eigentlich FORMULIERT!

Die Antwort auf diese Frage sollte nämlich NICHT "einen
Algorithmus" lauten, sondern "einen Automaten". (Eigentlich
"ein Automatennetz". Egal.) Das ist nämlich MEINER Meinung
nach das Wesentliche am Programmieren.

So. Jetzt gibt es das andere Problem: Wer C gelernt hat, bei
dem ist das Kind schon in den Brunnen gefallen, denn der hat
bereits verinnerlicht, dass man in einer Programmiersprache
"selbstverständlich" einen Algorithmus formuliert, also eine
Vorschrift, die nach endlich vielen Schritten zum Ergebnis
führt. Die (theoretisch zweitrangige) Prämisse der sequenziellen
Verarbeitung ist unauslöschlich in sein Hirn eingebrannt. Man
müsste also aus dieser Sackgasse erstmal rückwärts herausfahren
und den Gedanken popularisieren, dass man auch in klassischem
C das Verhalten von AUTOMATEN beschreibt, denn dann hat man
konkrete Anknüpfungspunkte für die Demonstration, wieso man
dieses und jenes in C++ BESSER als in C beschreiben kann.

Überspitzt ausgedrückt: Man muss auch beim Lehren von C die
Prämisse "stop teaching C" beherzigen!


Oder das Ganze NOCH kürzer:
Vieles, was über Programmierung gesagt wird, suggeriert, das
Programm beschriebe direkt die Sachverhalte der Anwendungs-
domäne.
Das ist Schwachsinn. Der Programmierer bildet die Sachverhalte
der Anwendungsdomäne in einen abstrakten Automaten ab, und
DIESER AUTOMAT wird mit den Mitteln der Programmiersprache
beschrieben. Die Gesamtabbildung ist nicht einstufig, sondern
zweistufig.
Nur diese Tatsache macht es möglich, unterschiedliche
Programmiersprachen einigermaßen effizient miteinander zu
vergleichen.

von Dr. Sommer (Gast)


Lesenswert?

Possetitjel schrieb:
> Ich darf mir JEDES Programm als Zusammen-
> schaltung von 74HCxx-ICs vorstellen. Es ist mathematisch
> beweisbar, dass diese Deutung zulässig ist!

Als Automaten-Theorie, Turing-Maschine oder gar Lambda-Kalkül erfunden 
wurden, gab es noch gar keine 74er-IC's, oder überhaupt irgendwelche 
Halbleiter. Tatsächlich hat die Informatik mit völlig abstrakten 
Beschreibungen von mathematischen Algorithmen angefangen, als es 
nichtmal Röhren gab. Die Informatiker haben hier also definitiv nicht 
wie Conquistadores die schönen Konstruktionen der Ingenieure 
durcheinander gebracht. Vor allem der Lambda-Kalkül ist komplett 
losgelöst von Dingen wie "Zustände" (Flipflops) und sequentieller 
Ausführung, auch wenn er bijektiv auf Turing-Maschinen abbildbar ist. 
Ausgehend von dieser theoretischen Basis wurden Programmiersprachen, 
Parser und auch heutige Bestandteile der Informatik entwickelt. Ob die 
jetzt auf Papier&Stift, Mechanische Rechner, Röhren-Rechner, 74er-Gräber 
oder integrierte CPU's ausgeführt werden ist komplett egal.
Viele der Begriffe wie "Klasse" oder "Funktion" kommen aus der 
Mathematik (Informatik = Informations-Mathematik), und klingen daher 
Un-Ingenieurisch, aber sind sie deswegen falsch?
Unbestritten ist in der Mathematik "f(x)=7*x" eine Funktion. In C wäre 
das dann z.B.
1
double f (double x) { return 7. * x; }
Soll man das jetzt nicht mehr Funktion nennen? Soll man es Automaten 
nennen  obwohl es überhaupt keinen Zustand ("Flipflops") hat?

Auch wenn es richtig ist dass prinzipiell jedes Programm einen Automaten 
beschreibt, braucht man dennoch höhere Abstraktionen, ja, Bürokratie, um 
der Komplexität Herr zu werden. Daher gibt es Datenstrukturen, welche 
Daten (und Daten sind ja das, um das sich alles dreht) als Black Boxen 
kapseln.  Dafür ist OOP, inklusive Dingen wie Vererbung, ein 
erwiesenermaßen äußerst nützliches Hilfsmittel. Dinge wie Interfaces 
scheinen nutzlose Bürokratie zu sein; genau wie der Dienstweg in 
komplexen Organisationen. Aber ohne versinkt schnell alles im Chaos. OOP 
geht auch in C und wird auch gemacht, z.B. im Linux-Kernel.

Würdest du auch Programme in rein funktionalen Sprachen als Automaten 
bezeichnen? Diese enthalten keine Anweisungen, beschreiben keinen 
Zustand, verändern keine Daten, lassen sich nur nichttrivial auf 
tatsächliche Rechner umsetzen, die wie "Automaten" aufgebaut sind. Sie 
bieten nur ein Mapping Eingabe->Ausgabe. Dennoch kann man alles damit 
berechnen.

Es ist übrigens sehr lehrreich mal 1-2 Module theoretische Informatik zu 
besuchen; dort werden die mathematischen Wurzeln der Informatik offenbar 
und warum die Informatik sich eben nicht als Hilfswissenschaft für 
Ingenieure sieht.
Außerdem finde ich dass die Ingenieurs-Wissenschaften auch nicht 
besonders zugänglich sind. Unmengen an kaputt-missbrauchter Mathematik 
und ebenso abgehobenen Begriffen machen die auch nicht leichter 
verständlich.

Überhaupt ist es spannend, wie hier (vermutlich) Ingenieure immer wieder 
erklären wie sie alles besser wissen als Informatiker. Machen andere 
Fachbereiche so etwas auch? Haben solche Ingenieure überhaupt genügend 
Informatik-Wissen um darüber urteilen zu können?

von Gerhard O. (gerhard_)


Lesenswert?

Jetzt trete ich mal (wie schon so oft) kräftig ins Fettnäpfchen:

Ich lese ja gerne mit und nichts liegt mir ferner als "Religion" zu 
machen. Von meiner begrenzten Vista kann ich nur kommentieren, daß die 
moderne Sprachenevolution höchstwahrscheinlich ihre Berechtigung und 
Grund hat um komplizierte (moderne) Probleme besser lösen zu können.

Ich sehe es an mir, bei den C++ Beispielen blicke ich ohne weitgehende 
Recherche nicht mehr durch. Mein Gehirn ist total auf das klassische 
Programmieren eingerastet. Klassische Sprachen verstehe ich. Ich muß 
alles verstehen und komplett sehen können. Bei Klassischen C u.ä. tut 
man sich da leicht. Wenn ich mir aber das neueste C++ ansehe kann ich 
die klare Logik nicht mehr verfolgen. Sorry. Es geht einfach nicht. Das 
ist mir dann zu abstrakt und versteckt. C++ auf Niveau z.B vieler 
Arduino Bibliotheken kann ich noch einigermaßen verstehen. Die neuesten 
Konzepte sind mir aber im Augenblick einfach noch zu abstrakt.

Da bei mir der Schwerpunkt meines Interesses auf uC liegt, komme ich 
praktisch mit C sehr gut zurecht. Hier schwimme ich in meinem 
natürlichen Element. Mit C++ bin ich zur Zeit noch aus meinem Element 
heraus.

Was ich damit sagen will ist, daß wahrscheinlich nur Leute mit den neuen 
Konzepten wirklich glücklich werden die noch nicht mit klassischen 
Programmieren vorbelastet sind. Wer also mit C++ und Objekt Konzepten 
groß wird für den ist das höchstwahrscheinlich intuitiv. Klassisches 
Programmierverständnis hindert hier massiv. Wer so wie ich mit 
klassischen Programmieren groß geworden ist, tut sich oft schwer so weit 
umzudenken. Auch wenn ich mir Mühe gebe, AHA Momente sind leider nur 
spärlich. Tut mir leid, es ist aber so.

Dann kommt noch dazu, daß man viel neuen Syntax und Konzepte lernen muß 
und sehr viel Zeit mit Studium der neuen Sprachen verbringen muß. Auch 
kenne ich niemand in meinem Umfeld der zusammen mit mir mal ein kleines 
praktisches Lehrprojekt machen würden.

Wenn es möglicherweise anderen ähnlich wie mir geht, dann müßte man 
daraus schließen, daß wenn dazu lernen nicht wirklich funktioniert man 
eben das akzeptieren sollte und mit den Methoden die man beherrscht die 
anfallenden Probleme lösen sollte. Ich fürchte, auch wenn ich mir sehr 
viel Mühe gebe würde, daß der Groschen einfach nicht bald genug fallen 
würde.

Nicht jeder muß für eine Firma arbeiten, die darauf besteht, daß man die 
gängigen Sprachen beherrscht um kommerziell damit arbeiten zu können. 
Deshalb finde ich es besser mit dem Missionarisieren hier im Forum gar 
nicht erst anzufangen und sich gegenseitig zu respektieren. Ich finde 
jedenfalls die vorgestellten Beispiele durchaus interessant und plane 
mich auch etwas damit zu befassen sobald meine Tool Chain funktioniert. 
Aber meine eigenen Projekte ziehe ich lieber so durch wie ich es eben 
gelernt habe.

So ihr seht, bei mir ist, wie man sagt, Hopfen und Malz verloren:-)

Also, macht weiter. Interessieren tut es mich schon was auf dem Gebiet 
der C++ Entwicklung so gemacht wird und zeigt wie man Probleme 
heutzutage löst.

Ich hoffe ich habe mich hier mit meinem Kommentar nicht zu sehr 
blamiert. Aber ich wollte nur mal berichten wie es von der anderen Seite 
des Zauns aussieht...


Schönen Tag noch,
Gerhard

von Dr. Sommer (Gast)


Lesenswert?

Hier noch ein Beispiel, eine einfache String-Konkatenation welche auch 
0-Bytes können soll. In C:
1
char* greeting (const char* firstName, size_t firstNameLength, const char* lastName, size_t lastNameLength, ) {
2
  const char a [] = "Hallo, ";
3
  char* res = malloc (sizeof (a) + firstNameLength + lastNameLength + 2);
4
  if (!res) return NULL;
5
  memcpy (res, a, sizeof (a));
6
  memcpy (res+sizeof (a), firstName, firstNameLength);
7
  res [sizeof (a)+firstNameLength] = ' ';
8
  memcpy (res+sizeof (a)+firstNameLength+1, lastName, lastNameLength);
9
  res [sizeof (a)+firstNameLength+lastNameLength+1] = ' ';
10
  return res;
11
}
Das beschreibt ziemlich eindeutig einen Automaten. Es werden 
nacheinander Daten-manipulierende Befehle abgearbeitet. In C++ und 
vielen anderen Sprachen sieht das so aus:
1
std::string greeting (const std::string& firstName, const std::string& lastName) {
2
  return "Hallo, " + firstName + " " + lastName;
3
}
Hier sieht man nicht mehr viel vom Automaten auch wenn die Hardware 
letztendlich einer ist. Ist es hier nicht viel sinnvoller in Form von 
Funktionen und Datenstrukturen zu denken? Die string-Klasse kapselt 
Daten, die greeting-Funktion bildet Daten auf andere Daten ab. Das auf 
Logik-IC's umzusetzen erfordert schon ziemliche Hirn-Verrenkungen, die 
hier nicht besonders nützlich sind.
Übrigens nutzt auch std::string die böse template-Metaprogrammierung, 
aber als Nutzer sieht man davon nichts.

von Dr. Sommer (Gast)


Lesenswert?

Gerhard O. schrieb:
> Wer also mit C++ und Objekt Konzepten
> groß wird für den ist das höchstwahrscheinlich intuitiv.

OOP stammt aus den 60ern/70ern, und C++ aus den 80ern... Wann hast du 
denn programmieren gelernt?

Beitrag #5447684 wurde vom Autor gelöscht.
von Gerhard O. (gerhard_)


Lesenswert?

Dr. Sommer schrieb:
> Gerhard O. schrieb:
>> Wer also mit C++ und Objekt Konzepten
>> groß wird für den ist das höchstwahrscheinlich intuitiv.
>
> OOP stammt aus den 60ern/70ern, und C++ aus den 80ern... Wann hast du
> denn programmieren gelernt?

In den 80er Jahren. Motorola 6800 ASM, HP-BASIC/QB45/7, viel 
Instrumentsteuerung mit HP-IB, 8051 Assembler, Delphi., C. LabVIEW.

Also alles Zeugs um man sich heutzutage nicht mehr viel schert. Altes 
Eisen...

Auch wenn, wie Du sagst die Grundlagen "modern" implementierter Konzepte 
teils schon betagt sind, bin ich damit nie konfrontiert worden. Formell 
habe ich mich also mit den heutigen Mainstream Werkzeugen nie damit 
befaßt. Machte also nur HW und embedded Sachen. Man bleibt eben oft 
lieber auf dem familiären Pfad. Für mich sind das eben die erwähnten 
Werkzeuge. Sachen wie Lambda Kalkül sind für mich leider ein Fremdwort.

Abgesehen davon habe ich mich damals hauptsächlich mit diskreten Logik 
Design befasst und viel Analog und Funktechnik. Programmieren war nur 
Mittel zum Zweck um Mikroprozessor/uC einsetzen zu können. Und das 
machte man damals eben mit ASM und C. Es bestand nie eine Notwendigkeit 
viel über den Tellerrand zu schauen weil die Werkzeuge die man kannte 
eben ausreichend waren um die anfallenden Probleme zu bewältigen. Man 
könnte auch dazu sagen, man stagnierte:-)

von Dr. Sommer (Gast)


Lesenswert?

Na, dann bist du auch ein bisschen selber schuld die "modernen" 
Techniken nicht zu kennen :-)
Das Lambda-Kalkül ist eine der ersten Programmiersprachen, praktisch der 
Prototyp aller funktionalen Sprachen, aus den 30er-Jahren. Sie hat keine 
praktische Bedeutung, ist aber theoretische Grundlage für viele wichtige 
Konzepte. Spannend daran ist dass die Sprache extrem simpel ist und noch 
nicht einmal Zahlen kennt, man damit aber dennoch alles berechnen kann 
(ist äquivalent zur Turing-Maschine) - "rechnen mit nichts".

von Gerhard O. (gerhard_)


Lesenswert?

Dr. Sommer schrieb:
> Hier noch ein Beispiel, eine einfache String-Konkatenation welche auch
> 0-Bytes können soll. In C:

Also auf jeden Fall eleganter und "Powerful" sieht das zweite Beispiel 
schon aus. Nur verstehe ich im Augenblick nicht wie es unter der Haube 
funktioniert. Da müßte man schon mit der String Library vertraut sein. 
Da scheint der Compiler die notwendige Funktionalität des Ausdruckes 
anhand des Syntax selber zu konstruieren anstatt eine traditionelle C 
String Funktion wählen zu müssen. Sehe ich das richtig oder rede ich 
hier Stuss?

Aber es illustriert wie man sich auf die Anwendung beschränken kann und 
sich nicht mit Implementierungsdetails verzetteln muß.

Gibt es Version vom GCC mit dem das auc auf uC funktionieren würde? 
Wilhelm warf ein, daß teilweise das nur auf größeren Systemen anwendbar 
ist und auf AVR es im Augenblick anscheinend noch nicht verfügbar ist.

von Gerhard O. (gerhard_)


Lesenswert?

Dr. Sommer schrieb:
> Na, dann bist du auch ein bisschen selber schuld die "modernen"
> Techniken nicht zu kennen :-)
> Das Lambda-Kalkül ist eine der ersten Programmiersprachen, praktisch der
> Prototyp aller funktionalen Sprachen, aus den 30er-Jahren. Sie hat keine
> praktische Bedeutung, ist aber theoretische Grundlage für viele wichtige
> Konzepte. Spannend daran ist dass die Sprache extrem simpel ist und noch
> nicht einmal Zahlen kennt, man damit aber dennoch alles berechnen kann
> (ist äquivalent zur Turing-Maschine) - "rechnen mit nichts".

Ich habe mir das Wiki dazu durchgelesen. Leider verstehe ich von der 
Unterliegenden Mathe zum Teil nur Bahnhof. Das ist mir zu theoretisch.

von Dr. Sommer (Gast)


Lesenswert?

Gerhard O. schrieb:
> Nur verstehe ich im Augenblick nicht wie es unter der Haube
> funktioniert.

Die Idee ist, dass man das auch nicht muss. Wenn man komplexe Systeme 
hat kann man unmöglich jede Komponente begreifen...

Gerhard O. schrieb:
> Da scheint der Compiler die notwendige Funktionalität des Ausdruckes
> anhand des Syntax selber zu konstruieren
Gewissermaßen... Die string-Klasse definiert einen eigenen "+"-Operator 
welcher alles Notwendige erledigt. Ist im Endeffekt eine Funktion mit 
komischem Namen, die hier aufgerufen wird.

Gerhard O. schrieb:
> Gibt es Version vom GCC mit dem das auc auf uC funktionieren würde?
Leider nicht. Die string-Klasse benötigt dynamischen Speicher, der auf 
kleinen AVR's problematisch ist. Man könnte sich etwas basteln (mit mehr 
templates...) was dort einsetzbar ist aber dann natürlich eingeschränkte 
Funktionalität hat. Vielleicht würde es reichen einen eigenen Allokator 
zu übergeben, ich hab das noch nicht versucht...

Gerhard O. schrieb:
> Ich habe mir das Wiki dazu durchgelesen. Leider verstehe ich von der
> Unterliegenden Mathe zum Teil nur Bahnhof. Das ist mir zu theoretisch.
Ja, für praktische Anwendung bringt das eh nichts. Wenn du mit 
funktionaler Programmierung anfangen möchtest kannst du dir Sprachen wie 
Lisp, Scala, Haskell, ... anschauen.

von Possetitjel (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Possetitjel schrieb:
>> Ich darf mir JEDES Programm als Zusammen-
>> schaltung von 74HCxx-ICs vorstellen. Es ist mathematisch
>> beweisbar, dass diese Deutung zulässig ist!
>
> Als Automaten-Theorie, Turing-Maschine oder gar Lambda-Kalkül
> erfunden wurden, gab es noch gar keine 74er-IC's,

Das war auch nicht meine Aussage.


> oder überhaupt irgendwelche Halbleiter.

Ich kenne durchaus Namen wie Zuse oder Babbage, und ich kenne
auch die Geschichten rund um die Enigma. Ach so... "Dreloba"
sagt Dir etwas?!


> Die Informatiker haben hier also definitiv nicht wie
> Conquistadores die schönen Konstruktionen der Ingenieure
> durcheinander gebracht.

Du missverstehst mich. Die "praktischen Informatiker"
haben das Land der Mathematiker und Logiker verwüstet.

Was ich oben über Programmierparadigmen schrieb, habe ich
mir ja zum größten Teil nicht selbst ausgedacht, sondern
mir nur mit unendlicher Mühe aus einigen wenigen sehr guten
Theoriebüchern zusammengeklaubt: Logik, Compilerbau, theo-
retische Informatik.

Die echt harte Arbeit bestand darin, die sehr nützlichen
theoretischen Begriffe in die Praxis rückzuübertragen.
In den Büchern über Programmierung und Programmiersprachen
findet man davon nämlich nix. Die verzetteln sich in den
sprachlichen Einzelheiten, die die Konzepte mehr verdecken
als erklären.


> Vor allem der Lambda-Kalkül ist komplett losgelöst von
> Dingen wie "Zustände" (Flipflops) und sequentieller
> Ausführung, [...]

GENAU DAS schrieb ich (in etwas anderen Worten) in meinem
ersten Beitrag.

> Viele der Begriffe wie "Klasse" oder "Funktion" kommen
> aus der Mathematik (Informatik = Informations-Mathematik),
> und klingen daher Un-Ingenieurisch, aber sind sie deswegen
> falsch?

Nein -- nicht deswegen.

Sie sind deswegen furchtbar, weil die praktischen Informatiker
die Mathematik so verhuntzen. Korrigiere mich, wenn ich falsch
liege, aber eine C-function, die eine static-Variable enthält,
ist doch genau KEINE zustandsfreie Funktion mehr, oder?

> Unbestritten ist in der Mathematik "f(x)=7*x" eine Funktion.
> In C wäre das dann z.B.double f (double x) { return 7. * x; }
> Soll man das jetzt  nicht mehr Funktion nennen?

Kommt auf den Kontext an.

> Soll man es Automaten nennen  obwohl es überhaupt keinen
> Zustand ("Flipflops") hat?

Das wäre durchaus ein sinnvoller Anfang. Wenn man weiter
vorn erklärt hat, was Automaten sind, ist die Auffassung
einer reinen Kombinatorik als Grenzfall eines Automaten
("entarteter Automat") sinnvoll, ja. Genauso ist ja die
Auffassung eines reinen Flipflops als Automaten ohne
weitere Kombinatorik sinnvoll.

> Auch wenn es richtig ist dass prinzipiell jedes Programm
> einen Automaten beschreibt, braucht man dennoch höhere
> Abstraktionen, [...]

Selbstverständlich. Dagegen habe ich nichts.

Ich habe überhaupt nichts gegen höhere Abstraktion, wenn
zuvor die einfachen, leicht zugänglichen Modelle und
Vorstellungen erklärt würden.

> Würdest du auch Programme in rein funktionalen Sprachen
> als Automaten bezeichnen?

Nein -- es SIND keine Automaten, aber sie beschreiben das
VERHALTEN von Automaten. Genau DAS wird ja durch die
bijektive Abbildbarkeit auf die Turing-Maschine garantiert!

Und genau DESWEGEN ist die Vorstellung mit den Automaten
so genial: Sie klappt auch, wenn "in Wahrheit" gar keine
Automaten da sind!

> Es ist übrigens sehr lehrreich mal 1-2 Module theoretische
> Informatik zu besuchen; dort werden die mathematischen
> Wurzeln der Informatik offenbar und warum die Informatik
> sich eben nicht als Hilfswissenschaft für Ingenieure sieht.

Mir ist relativ egal, wie sich die Informatiker selbst sehen.

Die theoretische Informatik steht sicher der Logik und der
Mathematik näher als den Ingenieurswissenschaften -- ganz
wie das auch in der theoretischen Elektrotechnik ist.

Die praktische oder angewandte Informatik IST für mich eine
Ingenieursdisziplin, genauso wie die Elektrotechnik.

> Außerdem finde ich dass die Ingenieurs-Wissenschaften auch
> nicht besonders zugänglich sind. Unmengen an kaputt-
> missbrauchter Mathematik und ebenso abgehobenen Begriffen
> machen die auch nicht leichter verständlich.

Mag sein... da bin ich sicher nicht der optimale Gesprächs-
partner; was die Elektrotechnik angeht, bin ich naturgemäß
sehr voreingenommen.
In einem gebe ich Dir aber Recht: Gute Dozenten sind rar,
und wirklich gute Lehrbücher auch. Die Suche wird nur etwas
vereinfacht, weil die Disziplinen schon etwas älter sind als
die Informatik, und sich die Spreu schon mehr vom Weizen
getrennt hat.


> Überhaupt ist es spannend, wie hier (vermutlich) Ingenieure
> immer wieder erklären wie sie alles besser wissen als
> Informatiker.

Du missverstehst mich.

Ich weiss keineswegs ALLES besser als die Informatiker. Mein
Zielpunkt ist nur genau eine Sache, nämlich die didaktisch
geschickte VERMITTLUNG gewisser Teile der angewandten
Informatik.
Eingefleischte Informatiker müssen damit notwendigerweise
Probleme haben -- sie haben nämlich die Scheuklappen auf, die
ICH als Elektrotechniker in der E-Technik habe. Mir war auch
lange Zeit schleierhaft, wie man den Unterschied von Strom
und Spannung nicht kennen kann, aber ich musste mich darauf
einstellen, dass es sehr vielen Laien so geht. Arroganz hilft
da nicht weiter.


> Haben solche Ingenieure überhaupt genügend Informatik-Wissen
> um darüber urteilen zu können?

Sagen wir es mal so: Da Du oben auffällig viele Sätze mit "Zwar
ist richtig, dass..." eingeleitet hast, kann die sachliche
Substanz dessen, was ich schrieb, SOOO verkehrt gar nicht
gewesen sein.

Ich stelle ja keine Behauptungen über den sachlichen Kern
der Informatik auf. Meine Aussage ist nur: Die übliche Form
der Lehre, der Darstellung lehrt meiner Meinung nach die
Dinge in einer ungünstigen Reihenfolge und mit falschen
Prioritäten.

Das ist in der Mathematik ganz genauso: Das, was als theo-
retisches Fundament der Mathematik angesehen wird, lernt man
KEINESWEGS in der 1. Klasse. Dort lernt man mathematische
Trivialitäten wie das Zahlenrechnen.
Die Grundlagen der Mathematik lernt eine winzige Minderheit
der Menschen -- nämlich im Mathematikstudium.

von Gerhard O. (gerhard_)


Lesenswert?

Jetzt ist mir noch eine Perspektive zum Thema eingefallen die vielleicht 
erklärt warum es vielen möglicherweise so wie mir geht.

Konzepte wie z.B Lambda Kalkül scheint mehr ein Hochschulthema zu sein 
wie frühere angewandte Problemlösung.

Wer ab den 70er Jahren mit Mikro/uC  Projekten arbeiten mußte, 
konzentrierte sich hauptsächlich mit den praktischen Problemen der HW/FW 
Implementierung. Man dachte hauptsächlich in Logik Terminologie und 
Algorithmen der Anwendung. Ich glaube nicht, daß die damaligen 
Ingenieure sich viel mit Informatik Theorie befaßt haben oder mußten. 
Alles drehte sich nur darum die HW zum Laufen zu bringen. Z.B ein 
Entwicklungsteam bei R&S konzentrierte sich damals eben das Meßgerät 
funktionsfähig zu machen.

Viele heutige Anwendungen die hauptsächlich mit Daten arbeiten, also 
dort wo die unterliegende HW nur noch Mittel zum Zweck ist, dort scheint 
die theoretische Informatik viel wichtiger geworden zu sein. Das sieht 
man ja im gesammten Internetanwendungsbreich und Frontier Sachen wie 
K.I.

Die Natur der Projekte hat sich also seit den 1970ern gewaltig geändert 
und eine gewisse Perspektive ist bitter notwendig. Auch wenn 
Maschinensteuerung immer noch aktuell ist, hat sich deren Verwirklichung 
total gewandelt. Deshalb sehe ich auch ein, daß die modernen Anwendungen 
andere Werkzeuge benötigen die eben mit den Anwendungen gewachsen sind 
oder müssen.

OK. Muß jetzt weg

Gerhard

von Possetitjel (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Wenn du mit funktionaler Programmierung anfangen
> möchtest kannst du dir Sprachen wie Lisp, Scala,
> Haskell, ... anschauen.

Frage am Rande: Aufgrund welcher Verschwörung fehlt
Tcl regelmäßig in solchen Aufzählungen?

(Die Frage ist völlig ernst gemeint; ich weiss viel zu
wenig von funktionaler Programmierung, um einen fundierten
Vergleich zwischen Tcl und Lisp anstellen zu könnnen.)

von Dr. Sommer (Gast)


Lesenswert?

Possetitjel schrieb:
> Sie sind deswegen furchtbar, weil die praktischen Informatiker
> die Mathematik so verhuntzen. Korrigiere mich, wenn ich falsch
> liege, aber eine C-function, die eine static-Variable enthält,
> ist doch genau KEINE zustandsfreie Funktion mehr, oder?

Logisch. Der Begriff wird beibehalten. Es wird daher auch teilweise nach 
"Prozedur" umbenannt. Funktionslokale statische nicht-konstante 
Variablen sind auch so ein typisches C-Unding.

Possetitjel schrieb:
> Ich habe überhaupt nichts gegen höhere Abstraktion, wenn
> zuvor die einfachen, leicht zugänglichen Modelle und
> Vorstellungen erklärt würden.
Ich finde OOP sehr intuitiv und verständlich. Kurioserweise haben 
meistens die E-Techniker Probleme damit, obwohl da eigentlich noch mehr 
in Komponenten und Black-Boxes gedacht wird (IC's, Platinen, Baugruppen, 
...).

Possetitjel schrieb:
> Die praktische oder angewandte Informatik IST für mich eine
> Ingenieursdisziplin, genauso wie die Elektrotechnik.
Für andere aber nicht. Ich merke deutlich die Unterschiede im Denken bei 
der Zusammenarbeit mit Ingenieuren.

Possetitjel schrieb:
> Die übliche Form
> der Lehre, der Darstellung lehrt meiner Meinung nach die
> Dinge in einer ungünstigen Reihenfolge und mit falschen
> Prioritäten.
Jeder lernt anders. Ich hätte mir auch eine andere Lehre gewünscht, aber 
auch nicht so wie du sie dir vorstellst. Man kann es nicht jedem Recht 
machen. Die sehr praktische Herangehensweise generiert schnelle 
Erfolgserlebnisse, was vielen beim Lernen hilft. Auch ein Grund warum 
z.B. Python viel besser für die Lehre geeignet ist als C...
Dass Theorie und Praxis weit auseinander liegen ist der typischen 
akademischen Organisation geschuldet. Und das ist in der E-Technik 
genauso - welcher E-Technik-Student kann einen Blinker mit NE555 bauen?

Possetitjel schrieb:
> Dort lernt man mathematische
> Trivialitäten wie das Zahlenrechnen.
Das ist auch das was 95% der Leute in ihrem Leben brauchen. Leider wird 
Mathe immer noch als uncool angesehen, es gilt schon als chic zu sagen 
"Mathe konnte ich nie". Bei Sprachen-Fächern sagt das keiner...
Wenn du in der 1. Klasse mit Definition der natürlichen, ganzen, 
rationalen, irrationalen Zahlen und Körpern anfängst und dann beweist 
dass R einer ist, hilft das absolut niemandem.

von Dr. Sommer (Gast)


Lesenswert?

Possetitjel schrieb:
> Frage am Rande: Aufgrund welcher Verschwörung fehlt
> Tcl regelmäßig in solchen Aufzählungen?

Weil das keine besonders verbreitete Sprache ist, und funktionale 
Programmierung nur ein Teilaspekt ist, im Gegensatz zu z.B. Haskell? In 
C++ kann man auch funktional programmieren, insbesondere das 
template-System ist quasi funktionale Programmierung.

von Datenlutscher (Gast)


Lesenswert?

Gerhard O. schrieb:
> Ich habe mir das Wiki dazu durchgelesen. Leider verstehe ich von der
> Unterliegenden Mathe zum Teil nur Bahnhof. Das ist mir zu theoretisch.
Lamdakalkül für Doofies: "Funktionen können Funktionen als Parameter 
haben."
Und schon hast du die funktionale Programmierung verstanden.

von Markus F. (mfro)


Lesenswert?

Dr. Sommer schrieb:
> char* greeting (const char* firstName, size_t firstNameLength, const
> char* lastName, size_t lastNameLength, ) {
>   const char a [] = "Hallo, ";
>   char* res = malloc (sizeof (a) + firstNameLength + lastNameLength +
> 2);
>   if (!res) return NULL;
>   memcpy (res, a, sizeof (a));
>   memcpy (res+sizeof (a), firstName, firstNameLength);
>   res [sizeof (a)+firstNameLength] = ' ';
>   memcpy (res+sizeof (a)+firstNameLength+1, lastName, lastNameLength);
>   res [sizeof (a)+firstNameLength+lastNameLength+1] = ' ';
>   return res;
> }

Ich kenne keinen C-Programmierer, der so was schreiben würde. Auch die 
Erfinder der String-Library haben sich dabei was gedacht.

Die Entsprechung zum C++-Beispiel sieht eher so aus:
1
 char *res = malloc(strlen(a) + strlen(firstName) + strlen(lastName) + 2);
2
 if (res != NULL)
3
      strcat(strcat(strcat(strcpy(res, a), firstName), " "), lastName);
4
 return res;

Ich gebe zu, längst nicht so schön wie die C++-Variante, aber deutlich 
"hübscher" und lesbarer als deine.

von Dr. Sommer (Gast)


Lesenswert?

Markus F. schrieb:
> Die Entsprechung zum C++-Beispiel sieht eher so aus:

Funktioniert nicht mit Strings die 0-Bytes enthalten. Zugegeben, das ist 
bei Real-Namen nicht besonders sinnvoll, aber es gibt oft Situationen wo 
man das braucht. Besonders effizient ist das ständige Iterieren mittels 
strlen auch nicht.

von Possetitjel (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Possetitjel schrieb:
>> Ich habe überhaupt nichts gegen höhere Abstraktion, wenn
>> zuvor die einfachen, leicht zugänglichen Modelle und
>> Vorstellungen erklärt würden.
>
> Ich finde OOP sehr intuitiv und verständlich.

OOP ist für mich ein einfaches und sehr sinnvolles Konzept,
das typischerweise auf eine für mich absolut unverständliche
Art erklärt wird.

Ich habe sie nur durch konsequentes Umdeuten aller Begriffe
in Kategorien der Automatentheorie verstanden, und ich werde
immer noch hippelig, wenn ich Auslassungen echter Informatiker
über OOP lesen muss. Ich kann den Frust darüber, wie man eine
einfache und sinnvolle Sache dermaßen frachtbriefmäßig
umständlich erklären kann, nur schlecht unterdrücken.


> Kurioserweise haben meistens die E-Techniker Probleme damit,
> obwohl da eigentlich noch mehr in Komponenten und Black-Boxes
> gedacht wird (IC's, Platinen, Baugruppen, ...).

Das ist sehr interessant, dass Du das sagst, weil ich mich in
meiner Vermutung bestätigt sehe, dass es nicht das Konzept
an sich ist, das die E-Techniker abstößt, sondern die Art und
Weise der Darstellung.

Es könnte sein, dass Wilhelm auf eine Art Recht hat, die ich
vorhin nicht gesehen habe: Möglicherweise erwerben Informatiker
trotz der Überbetonung von Sprachen und Grammatiken genügend
Wissen über Automatentheorie, so dass sich für sie die Konzepte
der OOP quasi nebenbei durch genaues Hinsehen erschließen.

E-Techniker haben diese Kenntnisse der Automatentheorie nicht
zwingenderweise; also entsteht da erstmal eine Blockade. Es
ist aber, um einigermaßen Programmieren zu können, gar nicht
notwendig, die Initiation durch TheoInf I + II über sich
ergehen zu lassen -- es genügt, den deutlich kleineren Teil
des Feldes zu beherrschen, der sich mit (endlichen) Automaten
befasst. Das wiederum sehen die Informatiker nicht, weil ihnen
mangels Notwendigkeit nicht bewusst ist, dass man Automaten-
theorie auch betreiben kann, ohne sich um die Korrespondenzen
zu den Grammatiken zu scheren.

von Markus F. (mfro)


Lesenswert?

Dr. Sommer schrieb:
> ... Strings die 0-Bytes enthalten...

das ist für C-Programmierer ein Oxymoron.

von Possetitjel (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Possetitjel schrieb:
>> Frage am Rande: Aufgrund welcher Verschwörung fehlt
>> Tcl regelmäßig in solchen Aufzählungen?
>
> Weil das keine besonders verbreitete Sprache ist, und
> funktionale Programmierung nur ein Teilaspekt ist, im
> Gegensatz zu z.B. Haskell?

Okay, das gibt Sinn. Danke.

von Niklas Gürtler (Gast)


Lesenswert?

Possetitjel schrieb:
> es genügt, den deutlich kleineren Teil des Feldes zu beherrschen, der
> sich mit (endlichen) Automaten befasst.

Endliche Automaten reichen da nicht, es muss mindestens bis zur Turing 
Maschine gehen damit übliche Programme abbildbar werden. Und dafür 
brauchts dann doch ein Semester.

Possetitjel schrieb:
> dass man Automaten- theorie auch betreiben kann, ohne sich um die
> Korrespondenzen zu den Grammatiken zu scheren.
Da das aber die Hauptanwendung ist gehört es irgendwie dazu.

In Anbetracht der Tatsache dass die meisten Informatiker TheoInf 
überhaupt nicht verstehen aber gewöhnliches OOP mit Kapselung und 
Datenstrukturen schon, würde ich nicht sagen dass es besonders hilfreich 
wäre Automaten als Grundlage für alles darzustellen. Eine String Klasse 
ist als Text intuitiver verstanden denn als Turing Maschine, wo auf dem 
Band Zeichen, Länge usw liegen. Schlimmer wird es z.B. bei Listen oder 
Graphen. Komplexe OOP-Strukturen sind da noch viel weiter entfernt...

Possetitjel schrieb:
> OOP ist für mich ein einfaches und sehr sinnvolles Konzept, das
> typischerweise auf eine für mich absolut unverständliche Art erklärt
> wird.
Für dich mag das zutreffen, aber ich glaube nicht dass das für die 
Mehrheit gilt. Das Konzept der Datenkapselung dürfte vielen besser 
liegen. Insbesondere weil die meisten Informatiker Begriffe wie 
Schaltwerk, Kombinatorik (in dem Zusammenhang), und 74er nie gehört 
haben.

von Dr. Sommer (Gast)


Lesenswert?

Markus F. schrieb:
> Dr. Sommer schrieb:
> ... Strings die 0-Bytes enthalten...
>
> das ist für C-Programmierer ein Oxymoron.

Dann halt Byte-Array. In den meisten Sprachen muss man sich um solche 
Probleme halt keine Sorgen machen...

PS: Ich würde im Studium eher noch mehr auf die Details der 
Programmiersprachen eingehen, und dafür Dinge wie Jura oder BWL 
reduzieren. Wenn ich sehe was so am Code produziert wird (insbesondere 
in C und C++) überkommt einen das Gruseln. In C sind viele Dinge einfach 
falsch und werden trotzdem wie selbstverständlich überall so gemacht...

von Ach ja ;) (Gast)


Lesenswert?

Markus F. schrieb:
> Dr. Sommer schrieb:
>> ... Strings die 0-Bytes enthalten...

... sind dann vorzeitig nullterminiert.

;)

http://www.c-howto.de/tutorial/strings-zeichenketten/nullterminiert/
1
char text[10] = "abcdefg";
2
printf("%s\n", text);
3
text[3] = '\0';
4
printf("%s\n", text);
5
6
abcdefg
7
abc

von Roland F. (rhf)


Lesenswert?

Hallo,

Dr. Sommer schrieb:

> PS: Ich würde im Studium eher noch mehr auf die Details der
> Programmiersprachen eingehen...

Was meinst du mit "Details"?

rhf

von TriHexagon (Gast)


Lesenswert?

Possetitjel schrieb:
> Es könnte sein, dass Wilhelm auf eine Art Recht hat, die ich
> vorhin nicht gesehen habe: Möglicherweise erwerben Informatiker
> trotz der Überbetonung von Sprachen und Grammatiken genügend
> Wissen über Automatentheorie, so dass sich für sie die Konzepte
> der OOP quasi nebenbei durch genaues Hinsehen erschließen.

Das ist komplett daneben. Ich habe fast zehn Jahre vor dem Studium mit 
dem Programmieren angefangen, direkt mit C# und OOP. Gerade Java und C# 
erzwingen OOP ja extrem. Da hatte ich keine Ahnung von Automatentheorie 
oder Ähnliches. Und trotzdem haben sich mir diese Konzepte erschlossen. 
Und ich war da nicht der Einzige, ein paar Jungs aus der Computer-AG 
haben das auch verstanden. Es ist einfach nicht nötig. Das Buch, dass 
ich damals verwendete, nutze die Analogie eines Autos oder eines 
Bauernhofes, bin mir nicht mehr so sicher. Auf jeden Fall so, dass es 
ein 0815 Mensch ohne jegliche Vorkenntnisse verstehen kann. Andererseits 
ist es im Studium auch so, dass viele im ersten Semester direkt mit Java 
anfangen, Theoretische Informatik kommt hingegen erst später.

Possetitjel schrieb:
> Ich habe sie nur durch konsequentes Umdeuten aller Begriffe
> in Kategorien der Automatentheorie verstanden, und ich werde
> immer noch hippelig, wenn ich Auslassungen echter Informatiker
> über OOP lesen muss. Ich kann den Frust darüber, wie man eine
> einfache und sinnvolle Sache dermaßen frachtbriefmäßig
> umständlich erklären kann, nur schlecht unterdrücken.

Genau das ist eben dein Problem, Umdeuten ist halt nicht Verstehen. Du 
bist von der Automathentheorie zu sehr vereinnahmt, weshalb du den 
Sachverhalt nicht mehr anders betrachten kannst. Die Betrachtungsweise 
musst du fallen lassen. Deswegen auch die Abneigung gegenüber der 
Vererbung, die aber ein essentieller Teil von OOP ist, weil sie mit 
"deiner Betrachtungsweise" nicht harmoniert.

von Possetitjel (Gast)


Lesenswert?

Niklas Gürtler schrieb:

> Possetitjel schrieb:
>> es genügt, den deutlich kleineren Teil des Feldes zu
>> beherrschen, der sich mit (endlichen) Automaten befasst.
>
> Endliche Automaten reichen da nicht, es muss mindestens
> bis zur Turing Maschine gehen damit übliche Programme
> abbildbar werden.

Es ging um die Frage, warum viele E-Techniker mit OOP
solche Probleme haben.

Um die Grundidee der OOP zu erklären, muss ich nicht
bis zur Turingmaschine gehen -- das habe ich nämlich
in meinem ersten, überlangen Beitrag schon getan.


> Possetitjel schrieb:
>> dass man Automatentheorie auch betreiben kann, ohne
>> sich um die Korrespondenzen zu den Grammatiken zu
>> scheren.
>
> Da das aber die Hauptanwendung ist gehört es irgendwie
> dazu.

Kein Zweifel: Hier spricht ein Informatiker.

Für mich liegt die Domäne der Automatentheorie in allen
Arten von Prozess- und Ablaufsteuerungen. Die Korrespondenz
zu den Grammatiken ist für mich ein winziges Spezialthema,
das nur für die theoretischen Informatiker wichtig ist.

Ich schreibe das nicht als Provokation, sondern weil es
die Wahrheit ist.
Ich hatte eine kleine Weile Berührung mit Steuerungs-
programmierung (SPS), und ich wäre völlig erschossen gewesen,
wenn ich nichts von endlichen Automaten gewusst hätte.

> In Anbetracht der Tatsache dass die meisten Informatiker
> TheoInf überhaupt nicht verstehen aber gewöhnliches OOP
> mit Kapselung und Datenstrukturen schon, würde ich nicht
> sagen dass es besonders hilfreich wäre Automaten als
> Grundlage für alles darzustellen.

Das beweist erstmal nur, dass die Art und Weise der
Darstellung von TheoInf schlecht ist.

> Eine String Klasse ist als Text intuitiver verstanden
> denn als Turing Maschine, wo auf dem Band Zeichen, Länge
> usw liegen.

Wenn ich "Automatentheorie" sage, dann denke ich primär
an ENDLICHE Automaten.

> Possetitjel schrieb:
>> OOP ist für mich ein einfaches und sehr sinnvolles Konzept,
>> das typischerweise auf eine für mich absolut unverständliche
>> Art erklärt wird.
>
> Für dich mag das zutreffen, aber ich glaube nicht dass das
> für die Mehrheit gilt. Das Konzept der Datenkapselung dürfte
> vielen besser liegen.

Ein "Objekt" IST ein (häufig endlicher) Automat.


> Insbesondere weil die meisten Informatiker Begriffe wie
> Schaltwerk, Kombinatorik (in dem Zusammenhang), und 74er
> nie gehört haben.

Das ist ja der Skandal!

von Possetitjel (Gast)


Lesenswert?

TriHexagon schrieb:

> Genau das ist eben dein Problem, Umdeuten ist halt
> nicht Verstehen.

Netter Versuch.

von Possetitjel (Gast)


Lesenswert?

Mist... überlesen:


Dr. Sommer schrieb:

> Possetitjel schrieb:
>> Die praktische oder angewandte Informatik IST für mich
>> eine Ingenieursdisziplin, genauso wie die Elektrotechnik.
>
> Für andere aber nicht. Ich merke deutlich die Unterschiede
> im Denken bei der Zusammenarbeit mit Ingenieuren.

Nur interessehalber: Welche sind das? Bzw. wie zeigen sie
sich?

von Carl D. (jcw2)


Lesenswert?

Possetitjel schrieb:
> Carl D. schrieb:
>
>> Manchmal kann der Erkenntnisstand der "Pioniere" aber
>> nicht auf Nachzügler warten.
>
> Es geht nicht um den Erkenntnisstand an sich, sondern
> um die Unfähigkeit oder die Unlust, die unter vielen
> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu-
> lieren, dass sie für andere leicht verständlich werden.
>
> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.
>
> Die geniale Erkenntnis zu haben ist 1%, sie verständlich
> zu formulieren und lehrbar zu machen, die restlichen 99%.

Aha, und worin leitet sich der Anspruch derer ab, die sich gedanklich 
auf das Vorgestellte nicht selber einlassen wollen, die Erkenntnisse 
mundgerecht vorgelegt zu bekommen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

@Possetitjel:

Ich habe mir die Mühe gemacht, deinen ellenlangen Beitrag von oben
durchzulesen, jetzt musst du dasselbe auch mit meinem tun ;-)

Alle anderen dürfen ihn gerne überspringen.

Wenn ich dich richtig verstehe, versucht du, sämtliche Eigenschaften von
Programmiersprachen auf Automaten abzubilden, um sie dadurch besser zu
verstehen. Kann es sein, dass du dich damit selber blockierst und so
somit genau das Gegenteil von dem erreichst, was du eigentlich
anstrebst?

Was du in deinen Beispielen mittels Automaten beschreibst, sind im
Wesentlichen Ablaufstrukturen (Sprünge, Unterprogrammaufrufe, Objekte
mit Memberfunktionen, Parallelität usw.). Im Gegensatz zu Assembler und
Ur-Fortran zeichnen sich moderne Sprachen aber durch weit mehr als nur
die von ihnen unterstützten Ablaufstrukturen aus, als da wären:

- Datentypen (numerisch, textuell, primitiv, zusammengesetzt, ...)

- Typsysteme (stark, schwach, statisch, dynamisch, flach, hierarchisch,
  ...)

- Möglichkeiten der Metaprogrammierung (Lisp-Makros, C++-Templates, ...)

- u.v.m.

Ich bin zwar Informatiker, beschäftige mich aber auch mit Elektronik und
sonstiger Technik. Deswegen versuche auch ich, meinem Verständnis
abstrakter Sachverhalte dadurch auf die Sprünge zu helfen, dass ich in
meiner Vorstellung kleine Maschinchen baue, die mit irgendetwas (wie
bspw. Daten, Programmcode, geometrische Objekte oder was auch immer)
gefüttert werden und daraus – entweder einmalig oder laufend wie am
Fließband – unter heftiger (vorgestellter) Geräuschentwicklung
irgendetwas anderes erzeugen.

Das funktioniert für viele Dinge (wie bspw. eine Programmschleife, einen
Stack und sogar die Synchronisation zwischen mehreren Prozessen) ganz
hervorragend, aber bei den in der obigen Aufzählung genannten Punkten
ist meine Phantasie nicht mehr in der Lage, solche Maschinchen zu
konstruieren. Für einige Dinge (wie bspw. Mehrfachrekursion) kann ich
zwar ein entsprechendes Maschinchen bauen, aber bei der Inbetriebnahme
verklemmt es sich oder zerfällt sogar in seine Einzelteile, weil meine
Vorstellungskraft für das Durchspielen der Bewegungsabläufe nicht
ausreicht.

Ich habe deswegen lange nach einem besseren Ersatz für diese Maschinchen
gesucht und schließlich auch gefunden:

  Mathematische Modelle

Diejenigen, die schon lange vor mir auf diese Idee kamen, habe ich
früher immer als unverbesserliche Theoretiker angesehen und ihre
unverständlichen Aussagen als Geschwurbel abgetan.

Der Punkt bei der Sache: Ich musste anhand einiger konkreter Probleme
erst einmal selber auf den Dreh kommen, um zu glauben, dass da etwas
dran ist. Danach hat plötzlich auch das Geschwurbel der anderen (naja,
vieler, nicht aller ;-)) für mich eine Bedeutung bekommen.

Endgültig die Augen aufgegangen sind mir, als ich begann, mich mit
funktionaler Programmierung zu beschäftigen. In der reinen FP gibt es
weder Abläufe noch Zustände, weswegen die Vorstellung von Maschinchen
schon per se zu nichts führen kann.

Mit mathematische Modellen hingegen kann man einige Dinge tun, die mit
den Maschinchen in meinem Kopf kaum möglich sind:

- Man kann sie leicht zu Papier bringen und damit komplizierte
  Gedankengänge auch außerhalb des Kopfs speichern.

- Man kann damit Beweise führen und sich so selber klar machen, das ein
  komplizierter Algorithmus, den man gerade geschrieben hat, auch
  wirklich in allen Kontexten das richtige Ergebnis liefert.

- Man kann sie transformieren. Eine praktische Anwendung davon ist es,
  Programmcode so umzuschreiben, dass er effizienter wird, ohne dabei
  Fehler einzubauen. Die Vorgehensweise ist letztendlich nichts anderes
  als geschickte Umformen mathematischer Terme. Konkrete Beispiele
  finden sich bspw. in dem Buch "Pearls of Functional Algorithm Design"
  von Richard Bird.

Immer wieder fallen mir bei schwierigen Problemen weitere Wege ein, die
zwar abstrakt anmuten, aber letztendlich dazu geeignet sind, hinderliche
Knoten in Gehirnwindungen zu lösen und damit die Problemstellung zu
vereinfachen.

Und das Beste dabei: Die Erkenntnisse, die man dabei gewinnt, lassen
sich nicht nur auf die FP, sondern mit leichten Einschränkungen auch auf
die klassische Programmierung in C oder C++ anwenden.

Was ich damit ausdrücken möchte: Die Informatiker, deren Geschwurbel du
nicht verstehst, sind entweder tatsächlich Dummschwätzer oder Angeber,
oder aber sie denken in Modellen, die sie persönlich zwar befähigen,
selbst schwierigste Probleme zu lösen, die sich aber leider nicht in
deine Welt der Automaten übersetzen lassen. Umgekehrt haben diese Leute
vielleicht (wenn sie sich nie damit beschäftigt haben) Schwierigkeiten
damit, sich ein zeitlich veränderliches Signal im Frequenzbereich
vorzustellen, was für einen Elektroingenieur nichts besonders ist.

von Possetitjel (Gast)


Lesenswert?

Carl D. schrieb:

> Possetitjel schrieb:
>> Carl D. schrieb:
>>
>>> Manchmal kann der Erkenntnisstand der "Pioniere" aber
>>> nicht auf Nachzügler warten.
>>
>> Es geht nicht um den Erkenntnisstand an sich, sondern
>> um die Unfähigkeit oder die Unlust, die unter vielen
>> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu-
>> lieren, dass sie für andere leicht verständlich werden.
>>
>> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.
>>
>> Die geniale Erkenntnis zu haben ist 1%, sie verständlich
>> zu formulieren und lehrbar zu machen, die restlichen 99%.
>
> Aha, und worin leitet sich der Anspruch derer ab, die sich
> gedanklich auf das Vorgestellte nicht selber einlassen
> wollen, die Erkenntnisse mundgerecht vorgelegt zu bekommen?

Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:

Der Anspruch leitet sich schlicht aus der normativen Kraft
des Faktischen ab: Wenn ich die Wahl zwischen einem
unverständlichen und einem klar verständlichen Buch habe,
dann wähle ich ganz sicher nicht das unverständliche. Eins
meiner wenigen Privilegien besteht darin, mir meine Lehrer
aussuchen zu können.

Es interessiert mich keinen Deut, wenn der Autor des ersten
ein verkanntes Genie, der Autor des zweiten Buches aber nur
gutes Mittelmaß ist.

Wer sich zu fein ist, Arbeit in verständliche Darstellung zu
stecken, der bleibt am Ende eben auch genau das: Unverstanden.

Das ist sein Problem, nicht meins.

von Carl D. (jcw2)


Lesenswert?

Possetitjel schrieb:
> Carl D. schrieb:
>
>> Possetitjel schrieb:
>>> Carl D. schrieb:
>>>
>>>> Manchmal kann der Erkenntnisstand der "Pioniere" aber
>>>> nicht auf Nachzügler warten.
>>>
>>> Es geht nicht um den Erkenntnisstand an sich, sondern
>>> um die Unfähigkeit oder die Unlust, die unter vielen
>>> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu-
>>> lieren, dass sie für andere leicht verständlich werden.
>>>
>>> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.
>>>
>>> Die geniale Erkenntnis zu haben ist 1%, sie verständlich
>>> zu formulieren und lehrbar zu machen, die restlichen 99%.
>>
>> Aha, und worin leitet sich der Anspruch derer ab, die sich
>> gedanklich auf das Vorgestellte nicht selber einlassen
>> wollen, die Erkenntnisse mundgerecht vorgelegt zu bekommen?
>
> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:
>
> Der Anspruch leitet sich schlicht aus der normativen Kraft
> des Faktischen ab: Wenn ich die Wahl zwischen einem
> unverständlichen und einem klar verständlichen Buch habe,
> dann wähle ich ganz sicher nicht das unverständliche. Eins
> meiner wenigen Privilegien besteht darin, mir meine Lehrer
> aussuchen zu können.
>
> Es interessiert mich keinen Deut, wenn der Autor des ersten
> ein verkanntes Genie, der Autor des zweiten Buches aber nur
> gutes Mittelmaß ist.

Warum liest und kommentierst du dann das erste Buch?

> Wer sich zu fein ist, Arbeit in verständliche Darstellung zu
> stecken, der bleibt am Ende eben auch genau das: Unverstanden.

Richtig, von manchen unverstanden.
Und nochmal, es gibt keinen Anspruch auf Erkenntnis und schon gar nicht 
in der Passivform.

> Das ist sein Problem, nicht meins.

Dann Versuch doch nicht, ihm das wegzunehmen.

von Ach ja ;) (Gast)


Lesenswert?

Yalu X. schrieb:
>
> Ich habe mir die Mühe gemacht, [.]einen ellenlangen Beitrag von oben
> durchzulesen ..
>
> Alle anderen dürfen ihn gerne überspringen.

Falls es dich interessiert, ich habe bei dir nicht das Gefühl "irgendein 
Geschwurbel" zu lesen im Gegensatz zu manch anderen Texten hier, die mir 
reichlich wirr und ohne erkennbaren Faden erscheinen. Ich frage mich nur 
gerade angesichts vieler alltäglicher Programmieraufgaben, welche 
speziellen Applikationen es denn überhaupt notwendig machen den Pfad des 
"normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer 
völlig anderen Herangehensweise bedienen zu müssen?

von Gerhard O. (gerhard_)


Lesenswert?

Ach ja ;) schrieb:
> Ich frage mich nur
> gerade angesichts vieler alltäglicher Programmieraufgaben, welche
> speziellen Applikationen es denn überhaupt notwendig machen den Pfad des
> "normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer
> völlig anderen Herangehensweise bedienen zu müssen?

Jetzt wage ich mich nochmals aufs Eis:

Ich stelle mir vor, daß im herkömmlichen Feld der Hardware intensiven 
Steueraufgaben traditionelle Methoden immer noch sinnreich und 
vernünftig sind weil man tonnenweise eine wiederverwendbare, verläßliche 
und bewährte Codebasis hat.

Es sind eher die modernen Applikation wie IoT, Internet verbundener 
Sachen die sehr Daten intensiv und von Protokollen abhängig sind und 
viel kommunizieren wo die neuen Werkzeuge dem Designer das Leben 
leichter machen. Es gibt ja heute so viele Aufgaben die aus 90% GUI und 
Communication und der Rest bestehen und irgendwelche einfache Steuer- 
und Meßaufgaben abarbeiten. Da sehe ich zumindest die Vorteile und man 
sollte sie nützen sofern man es kann:-)

Als eingefleischter Praktiker tue ich mir im Augenblick schwer mich mit 
der neuen Materie vertraut zu machen. Aber vielleicht klappt es allen 
anfänglichen Schwierigkeiten zum Trotz doch einmal.

Abgesehen davon hängt Vieles davon ab welche Entwicklungswerkzeuge und 
uC Ressourcen vorhanden sind. Viele der neuen Tols benötigen eher 
großzügige Ressourcen und sind auf kleinen uC eher mißplaziert.

Wie Arduino beweist ist der Gebrauch eines Subsets von C++ durchaus 
realistisch und würde persönlich mehr Zeit und Muße dort reinstecken 
wollen um zumindest auf dieser Ebene etwas kompetenter zu sein.

Die Experten auf diesen Gebiet wissen sowieso wie sie ihre 
Projektprobleme lösen wollen und können und brauchen keine 
Besserwisser:-)

Ok. Das wärs so ziemlich für mich was dieses Thema angeht. Ich brauche 
mir nicht meine Brötchen damit zu verdienen und kann mir aussuchen was 
ich noch lernen will. Vielleicht fällt doch irgendwann der Groschen. Ich 
werde sicherlich verfolgen was auf diesem Gebiet noch erörtert wird.

Tut mir leid wenn ich Euch mit meinen Betrachtungen und Meinungen zu 
Tode gelangweilt habe. Mir war es nur wichtig mal die andere Seite 
aufzuzeigen.

Schönes Wochenende noch,
Gerhard

von TriHexagon (Gast)


Lesenswert?

Ach ja ;) schrieb:
> Yalu X. schrieb:
>>
>> Ich habe mir die Mühe gemacht, [.]einen ellenlangen Beitrag von oben
>> durchzulesen ..
>>
>> Alle anderen dürfen ihn gerne überspringen.
>
> Falls es dich interessiert, ich habe bei dir nicht das Gefühl "irgendein
> Geschwurbel" zu lesen im Gegensatz zu manch anderen Texten hier, die mir
> reichlich wirr und ohne erkennbaren Faden erscheinen. Ich frage mich nur
> gerade angesichts vieler alltäglicher Programmieraufgaben, welche
> speziellen Applikationen es denn überhaupt notwendig machen den Pfad des
> "normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer
> völlig anderen Herangehensweise bedienen zu müssen?

Weil mal das eine Paradigma Vorteile gegenüber andere in gewissen 
Situationen bietet. Vor allem, was soll denn dieser "normale intuitiver 
Lösungsansatz" sein? Ist das frei nach dem Moto "wer nur einen Hammer 
kennt, sieht in jedem Problem nur einen Nagel"? Es gibt auch in diesem 
Fall nicht diesen einen intuitiven Lösungsansatz. Jeder scheint darunter 
auch etwas anderes zu verstehen, für den einen ist die 
Metaprogrammierung in C++ absolut schlüssig und vorteilhaft, der andere 
verabscheut gleich " aufgeblassene, bürokratische" Hochsprachen und 
nimmt immer Assembler...

von Wilhelm M. (wimalopaan)


Lesenswert?

Oh, die Diskussion ist ja ganz woanders ...

Possetitjel schrieb:
> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:
>
> Der Anspruch leitet sich schlicht aus der normativen Kraft
> des Faktischen ab: Wenn ich die Wahl zwischen einem
> unverständlichen und einem klar verständlichen Buch habe,
> dann wähle ich ganz sicher nicht das unverständliche. Eins
> meiner wenigen Privilegien besteht darin, mir meine Lehrer
> aussuchen zu können.

Ich verstehe dieses Forum immer noch als Hilfe zur Selbsthilfe und ich 
habe nicht den Anspruch hier Kapitel eines Lehrbuches abzuliefern oder 
alles vorzuverdauen. Es geht mir nur um Anregungen. Wer nicht die 
Vorstellungskraft hat, dahinter einen Wert zu erkennen, der ihn dazu 
bringt, sich selbst(!) damit zu beschäftigen, der soll es eben sein 
lassen. Wer also ein Motiv hat, kann ja fragen. Ich bin kein 
Motivationstrainer sondern gehe von instrinsischer Motivation aus. 
Gerade in diesem Forum!

Und alles auf einen Automaten zurückzuführen finde ich ähnlich 
abenteuerlich wie das oben Yalu geschrieben hat. Ich finde die Modelle 
und Werkzeuge der theoretischen Informatik sehr nützlich, vor allem, 
weil man es mit Papier und Bleistift erledigen kann, allerdings kann ich 
auch verstehen, dass hier ggf. das Abstraktionsvermögen anderer aufhört.

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:

> Als eingefleischter Praktiker tue ich mir im Augenblick schwer mich mit
> der neuen Materie vertraut zu machen. Aber vielleicht klappt es allen
> anfänglichen Schwierigkeiten zum Trotz doch einmal.

Aus meiner Sicht sollte man sich die folgenden Fragen (ausgehend von 
einer C-Welt) stellen:

* wann kann/soll der Berechnungszeitpunkt sein: Compilezeit, 
Auführungszeit
* kann ich das Typsystem der Sprache modifizieren: ja/halb/nein
* wie/wann kann ich das Typsystem modifizieren: statisch im Quelltext, 
durch Berechnung zur Compilzeit, zur Laufzeit

Das Typsystem ist deswegen so wichtig, weil es der Kern der 
imperativ/prozeduralen Sprachen wie C oder C++ (hat noch mehr 
Paradigmen) ist.

In C kann ich keine Berechnungen zur Compilezeit machen und ich kann nur 
das eingebaute Typsystem verwenden. Somit ist es sehr schwer, 
abstrakteren Code zu schreiben. Je komplizierter die Aufgabe, desto mehr 
Abstraktion ist notwendig, um das Problem beherrschen zu können.

In C++ kann man:

* Berechnungen zur Compilezeit durchführen: der Compiler "interpretiert" 
den Code im Moment des Compilierens

* das Typsystem modifizieren, etwa einen Datentyp erfinden, der beim 
inkrementieren bei bspw. 10 saturiert oder zirkulär die Werte 0...9 
annimmt. Oder einen Datentyp String, der von der C-orientieren 
Sichtweise einzelner Zeichen abstrahiert, die es erlaubt, Strings zu 
addieren/konkatenieren (+) oder lexikografisch zu vergleichen (<).

* die Modifikation des Typsystems kann im Quelltext statisch stattfinden 
(Klassen erstellen) oder zur Compilezeit "berechnet" werden. Wenn es 
bspw. bekannt ist, dass ein Array maximal 100 Elemente enthält, reicht 
als DT für den Index ein uint8_t aus, es muss kein size_t sein. Das kann 
der Compiler zur Compilezeit selbst ermitteln.

Dies sind ein paar Dinge, die das Abstraktionsniveau erhöhen und damit 
Fehler vermeiden helfen, z.B. unerwünschter Wrap-around bei zu kleinen 
Ganzzahltypen, und die erstmal mit OOP in engeren Sinne, also 
Laufzeitpolymorphie (Liskov) gar nichts zu tun haben.

> Ok. Das wärs so ziemlich für mich was dieses Thema angeht.

Vielleicht sind die o.g. Dinge eine kleine Motivation, etwas tiefer 
einzusteigen.

von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> Vielleicht sind die o.g. Dinge eine kleine Motivation, etwas tiefer
> einzusteigen

Wilhelm,

Ist es schon und bedanke mich auch für Deine Hinweise.

Aber der Appettit kommt mit dem Essen und es ist notwendig eine 
Entwicklungsumgebung zu installieren die das auch kann. Ich kann nur 
lernen wenn ich mich damit praktisch befassen kann. Nur darüber zu lesen 
ist zwecklos für mich.

Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio 
zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das 
ideal weil es in Windows lauffähig sein müßte.

Den CYgwin GCC compiler wollte ich installieren, hatte aber Internet 
Verbindungsprobleme und das Installierprogramm gab auf. Da müßte ich mal 
rausfinden warum das nicht geht.


Also halte mir den Daumen,
Gerhard

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:

> Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio
> zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das
> ideal weil es in Windows lauffähig sein müßte.

Natürlich, man lernt auf dem PC, und MSVS ist ok, wenn es recht aktuell 
ist.

> Also halte mir den Daumen,
> Gerhard

Klaro - und bei Fragen ... fragen

von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> Gerhard O. schrieb:
>
>> Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio
>> zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das
>> ideal weil es in Windows lauffähig sein müßte.
>
> Natürlich, man lernt auf dem PC, und MSVS ist ok, wenn es recht aktuell
> ist.
>
>> Also halte mir den Daumen,
>> Gerhard
>
> Klaro - und bei Fragen ... fragen

Ok. Danke. Werde Dich beim Wort nehmen:-)

von Gerhard O. (gerhard_)


Lesenswert?

Im vorherigen Beitrag beschriebst Du die Compile Möglichkeiten. Das hört 
sich toll an obwohl ich mir im Augenblick noch wenig darunter vorstellen 
kann wie das im Einzeln vor sich geht. Deshalb wäre Experimentation 
wahrscheinlich der beste Weg um dafür ein praktisches Gefühl dafür zu 
bekommen.

Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo 
das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man 
mal recherchieren inwieweit deren GCC Compiler uptodate ist.

PC Apps programmieren tue ich eigentlich sonst nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:

> Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo
> das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man
> mal recherchieren inwieweit deren GCC Compiler uptodate ist.

GCC für ARM hat auch ein libstdc++.
Aber das Testen Deiner Programme ist doch auf dem PC in einer IDE viel 
einfacher. Später machst Du den Übergang zu µC.

von Ach ja ;) (Gast)


Lesenswert?

TriHexagon schrieb:
> was soll denn dieser "normale intuitiver
> Lösungsansatz" sein?

Wie ja jeder weiß, entsteht Software stets ingenieursmäßig durch 
ausgefuchstes, intensives Modellieren streng nach Entwicklungsplan, wie 
aus dem Lehrbuch und jeder der auch nur eine Zeile Code schreibt, bevor 
nicht auch der letzte Detailentwurf ausgearbeitet und auf Folie 
präsentiert ist, der ist ein ganz, ganz schlimmer Mensch. :)

Oder vielleicht eher doch nicht?

Das wäre dann der erwähnte eher intuitive Lösungsansatz. Soll heißen, 
natürlich schon ein paar Gedanken machen wo es hingehen soll, aber dann 
auch zügig anfangen zu Programmieren, um schnell erste Ergebnisse zu 
haben.

Wie jeder persönlich da vorgeht (oder vorgehen muss, weil's der 
Arbeitgeber bestimmt) und welcher Mittel er sich dabei bedient muss 
natürlich jeder für sich selber entscheiden. Yalu beispielsweise baut 
sich gedanklich seine kleinen Maschinchen, die er anschließend mit Daten 
füttert, in der Hoffnung, dass hinterher auch das "richtige" bei 
rauskommt. Inzwischen hat er diesen Ansatz aber wohl hinter sich 
gelassen.

Gerhard greift auf den Fundus seiner wiederverwendbaren und 
verlässlichen Codebasis zurück. Dr. Sommer wird seinen C++ -Kasten in 
Schwung bringen. Von einem hier in Forum las ich mal Nim hätte es ihm 
angetan. Der Admin (Schwarz) schwört wohl auf Python und Ruby (las ich 
mal). Es soll auch manche hier geben, die ihr Glück in einem 
Bezahl-BASIC gefunden haben. Mein Eindruck ist jeder ist da seinen 
Gewohnheiten irgendwie erlegen und nimmt halt das was er beherrscht. Was 
natürlich niemandem daran hindert auch neue Pfade auszuprobieren.

Was den Hammer betrifft, eine Software ist nicht ein simples 
Metall-Hau-Werkzeug, dass jeder in schneller Anlernmanier mal eben 
austauschen kann. Eine lieb gewonnene Radfahr-Gewohnheit auf dem eigenen 
Rennrad lässt sich auch nicht so einfach gegen die auf einem (fremden) 
Tandem eintauschen. Das ist nun mal nicht das gleiche bzw. fühlt sich 
völlig anders an. Genau so sieht es auch mit einer langjährig eingeübten 
Programmiersprache oder einem Programmier-Paradigma wie OOP vs. 
Prozedurales Programmieren aus. So ein Wechsel ist nicht mal eben auf 
die Schnelle gemacht. Nicht wenige scheitern ja schon am Eingewöhnen an 
FreeCAD oder an den MS Office Ribbons ;-) oder wie ich letztens las 
proggen lieber auf der Linux Kommandozeile in C, weil's so schön einfach 
geht anstatt sich mit der aufgeblasenen MS Visual C++ IDE 
herumzuschlagen. :)

Es kommt hinzu, mit zunehmendem Alter nimmt die einstige studentische 
Ausprobier-Euphorie auch eher steil ab. Da ist der Alltag einfach anders 
(straffer) strukturiert und die Zeit für viel Experimentierfreude nicht 
mehr so vorhanden. Also nimmt man was man kennt und gut ist.

:)

von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm M. schrieb:
> Gerhard O. schrieb:
>
>> Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo
>> das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man
>> mal recherchieren inwieweit deren GCC Compiler uptodate ist.
>
> GCC für ARM hat auch ein libstdc++.
> Aber das Testen Deiner Programme ist doch auf dem PC in einer IDE viel
> einfacher. Später machst Du den Übergang zu µC.

Das stimmt und hatte ich sowieso vor. Bevor ich nicht ein gewisses Maß 
Selbstvertrauen diesbezüglich erworben habe, hätte es wenig Sinn auf dem 
uC zu experimentieren.

Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings 
wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen 
da ich zur Zeit noch nichts habe.

Wie ist eigentlich z.B mit der Stringdoku?

Wenn ich jetzt eine String search machen wollte, geht das mit 
trickreicher Operator Magie oder Funktionsaufruf alleine? Das sind so 
die Fragen die ich mir beantworten muß. Auch wie ein Minimal Program 
aufgebaut sein müßte und die notwendigen Header Files. Da habe ich noch 
einiges vor mir. Naja, Dein Beispielprogram vorher, gibt mir da schon 
einen Start.

Laßt Euch von mir überraschen...

von Gerhard O. (gerhard_)


Lesenswert?

Ach ja ;) schrieb:
> Oder vielleicht eher doch nicht?

Ich bin ein ganz schlimmer Mensch:-)

Da ich meist meine eigene HW entwickle denke ich auch schon parallel mit 
wie die HW Gestaltung Aspekte die zukünftige SW beeinflussen würde um 
unnötige SW Klimmzüge zu vermeiden. Dann, wenn die HW existiert teste 
ich alles durch und schreibe und teste mal zuerst die Treiber oder 
verwende schon vorhandene Treiber von vorherigen Projekten, so daß man 
die Peripherie ansprechen kann. Dafür habe ich mir ein Standard Test 
Program geschneidert mit dem ich meine HW dann virtualisieren kann und 
testen. Da habe ich dann sofort Zugang auf die meisten Peripherien des 
uC, extern oder intern.

Die eigentliche SW wird erst dann wirklich geplant und detailliert. Da 
man zu diesem Zeitpunkt weiß was HW mäßig funktioniert oder nicht, macht 
dann die spätere Arbeit viel weniger nervig.

: Bearbeitet durch User
von Possetitjel (Gast)


Lesenswert?

Carl D. schrieb:

>> Es interessiert mich keinen Deut, wenn der Autor des
>> ersten ein verkanntes Genie, der Autor des zweiten
>> Buches aber nur gutes Mittelmaß ist.
>
> Warum liest und kommentierst du dann das erste Buch?

Das tue ich nicht.

Ich habe DIR geantwortet, nicht Wilhelm oder sonstwem.
Es war DEINE elitäre Behauptung, die "Pioniere" könnten
nicht auf jeden Nachzügler warten.

Meine Antwort DARAUF ist: Wenn sich die "Pioniere" zu
fein sind, sich allgemeinverständlich auszudrücken,
sollen sie nicht rumheulen, dass man sie nicht versteht.
Ursache -- Wirkung. Kausalität.

Mit Wilhelm hat das nix zu tun. Mich nerven Deine elitären
Unterstellungen.

von Possetitjel (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Possetitjel schrieb:
>> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:
>>
>> Der Anspruch leitet sich schlicht aus der normativen Kraft
>> des Faktischen ab: Wenn ich die Wahl zwischen einem
>> unverständlichen und einem klar verständlichen Buch habe,
>> dann wähle ich ganz sicher nicht das unverständliche. Eins
>> meiner wenigen Privilegien besteht darin, mir meine Lehrer
>> aussuchen zu können.
>
> Ich verstehe dieses Forum immer noch als Hilfe zur Selbsthilfe

Du hast aber schon gelesen, dass ich den Abschnitt überschrieben
habe mit "Auch wenn das wenig bis nichts mit Wilhelm zu tun hat"?


> und ich habe nicht den Anspruch hier Kapitel eines Lehrbuches
> abzuliefern oder alles vorzuverdauen. Es geht mir nur um
> Anregungen.

Das verstehe ich.

Eine Anregung hat ja aber den Sinn, Lust auf mehr zu machen.
Das erreichen Deine Anregungen aber bei mir nicht, sie
schrecken mich eher ab.

Der Grund dafür liegt darin, dass Deine Anregungen zu wenig
an das anknüpfen, was ich kenne.
Das kannst Du natürlich als Unverschämtheit und als Anspruchs-
haltung interpretieren -- aber es ist erstmal nur eine sachliche
Aussage. Was Du damit anfängst, ist Deine Sache.

> Und alles auf einen Automaten zurückzuführen finde ich
> ähnlich abenteuerlich wie das oben Yalu geschrieben hat.

Steht Dir völlig frei.
Im Gegensatz zu Dir formuliert Yalu seine Zweifel und Fragen
an mich ausführlich und gibt mir die Chance, mich zu erklären.

> Ich finde die Modelle und Werkzeuge der theoretischen
> Informatik sehr nützlich,

Ich auch.
Zu den Modellen und Werkzeugen der theoretischen Informatik
gehören allerdings auch die Automaten. Insofern verstehe ich
Deine Bemerkung von oben nicht. Immerhin ist die Turing-Maschine
auch ein Automat.

Ich habe auch nirgendwo gegen die theoretische Informatik
polemisiert. Meine Aussage war nur, dass die Bücher über
PROGRAMMIERSPRACHEN, die ich kenne, Scheisse sind, weil sie
sich in Details verlieren, die die Konzepte eher verdecken
als erklären. Das hat wenig bis nichts mit theoretischer
Informatik zu tun.

> vor allem, weil man es mit Papier und Bleistift erledigen
> kann, allerdings kann ich auch verstehen, dass hier ggf.
> das Abstraktionsvermögen anderer aufhört.

???

Ich pflege die Automatentheorie, die ich brauche, fast immer
mit Papier und Bleistift zu erledigen.

Und woher weisst Du, wo mein Abstraktionsvermögen endet?

von Carl D. (jcw2)


Lesenswert?

Possetitjel schrieb:
> Carl D. schrieb:
>
>>> Es interessiert mich keinen Deut, wenn der Autor des
>>> ersten ein verkanntes Genie, der Autor des zweiten
>>> Buches aber nur gutes Mittelmaß ist.
>>
>> Warum liest und kommentierst du dann das erste Buch?
>
> Das tue ich nicht.
>
> Ich habe DIR geantwortet, nicht Wilhelm oder sonstwem.
> Es war DEINE elitäre Behauptung, die "Pioniere" könnten
> nicht auf jeden Nachzügler warten.
Den Begriff "Pionier" haben ich als leicht überzeichneten Gegensatz zu 
den "was wir immer gemacht haben, hat uns immer gereicht"-Schreibern 
gewählt. Ich hab nichts gegen diese, möchte mich im Gegenzug von ihnen 
aber auch nicht bremsen lassen.

> Meine Antwort DARAUF ist: Wenn sich die "Pioniere" zu
> fein sind, sich allgemeinverständlich auszudrücken,
> sollen sie nicht rumheulen, dass man sie nicht versteht.
> Ursache -- Wirkung. Kausalität.
Sie sind "sich zu fein" auch denen, denen die Happen warum auch immer zu 
groß sind, diese vorzukauen.

> Mit Wilhelm hat das nix zu tun. Mich nerven Deine elitären
> Unterstellungen.

Wenn es elitär sein sollte, sein Hirn für mehr zu benutzen als die 
Ausrede "ich kann's nicht probieren, weil meine 9 Kollegen das nie 
verstehen", dann muß ich mich damit abfinden.

Aber was soll's, ich hatte eigentlich den Plan, mal ein Beispiel zu 
bauen, das komplex genug ist, um die Vorteile erkennbar zu machen und 
einfach genug, daß es auch mit leichter mental-Gastritis verdaubar ist. 
Offenbar kann ich mir die Zeit sparen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:

> Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings
> wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen
> da ich zur Zeit noch nichts habe.
>
> Wie ist eigentlich z.B mit der Stringdoku?

Die offizielle Doku zur Sprache und zur libstdc++ findest Du hier:

http://en.cppreference.com/w/


> Wenn ich jetzt eine String search machen wollte, geht das mit
> trickreicher Operator Magie oder Funktionsaufruf alleine?

Mmh, jetzt bin ich etwas verwirrt: ich war davon ausgegangen, dass Du 
ein Grundverständnis von C++ hast?

Der Typ std::string ist kein primitiver DT in C++, sondern in der 
libstdc++ definiert (eigentlich als template-Spezialisierung).

Grundsätzlich gilt in der libstdc++ eine Zweiteilung in (generische) 
Algorithmen und Datentypen. Das Bindeglied zwischen beidem sind 
Iteratoren. Iteratoren kann man im ersten Ansatz als verallgemeinerte 
Zeiger ansehen (DT mit den Op * ,-> ,++, !=).

Eine Substring-Suche findest Du als Elementfunktion des DT std::string. 
Andere Algorithmen auf den Containern in der Algorithmus-Teilbibliothek.

Ist das jetzt alles neu für Dich?

Würde auch vorschlagen, das Du andere Threads eröffnest, um Deine Fragen 
zu stellen.

von Gerhard O. (gerhard_)


Lesenswert?

Wilhelm,

Um diese Zeit hätte ich jetzt keine Antwort mehr erwartet:-) bei mir ist 
es fast 23:00 Uhr.

Wilhelm M. schrieb:
> Gerhard O. schrieb:
>
>> Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings
>> wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen
>> da ich zur Zeit noch nichts habe.
>>
>> Wie ist eigentlich z.B mit der Stringdoku?
>
> Die offizielle Doku zur Sprache und zur libstdc++ findest Du hier:
>
> http://en.cppreference.com/w/
Danke.
>
>> Wenn ich jetzt eine String search machen wollte, geht das mit
>> trickreicher Operator Magie oder Funktionsaufruf alleine?
>
> Mmh, jetzt bin ich etwas verwirrt: ich war davon ausgegangen, dass Du
> ein Grundverständnis von C++ hast?
Noch nicht viel weil ich bis jetzt uC nur in C gequält habe. Ich 
modifizerte allerdings die Core Serial vom Arduino um RS485 native zu 
unterstützen. Das ist auch alles und kam auch ganz gut zurecht damit 
weil da ja schon ein funktionierendes Beispiel vorhanden war das ich nur 
erweitern mußte.
>
> Der Typ std::string ist kein primitiver DT in C++, sondern in der
> libstdc++ definiert (eigentlich als template-Spezialisierung).
>
> Grundsätzlich gilt in der libstdc++ eine Zweiteilung in (generische)
> Algorithmen und Datentypen. Das Bindeglied zwischen beidem sind
> Iteratoren. Iteratoren kann man im ersten Ansatz als verallgemeinerte
> Zeiger ansehen (DT mit den Op * ,-> ,++, !=).
>
> Eine Substring-Suche findest Du als Elementfunktion des DT std::string.
Ok. Werde ich nachschauen. Ich beginne zu verstehen. Das ist definitiv 
sehr "powerful".
> Andere Algorithmen auf den Containern in der Algorithmus-Teilbibliothek.
Vielen Dank. Das werde ich mir gleich vorknöpfen weil es für mich 
praktisch wichtig ist.
>
> Ist das jetzt alles neu für Dich?
Absolut. Bis jetzt kam ich ja mit C immer zurecht. Will aber meinen 
Horizont doch erweitern weil mir einige C++ Sachen beim Arduino als sehr 
nützlich vorkamen.
>
> Würde auch vorschlagen, das Du andere Threads eröffnest, um Deine Fragen
> zu stellen.
Da hast Du recht. Werde ich machen.

Beitrag "Praktische C++ Anwendungsfragen"

Jedenfalls bin ich Dir für alle Deine Ratschläge und Informationen 
dankbar.


Gruß,
Gerhard

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Roland F. schrieb:
> Was meinst du mit "Details"?
u.a.:
- "using namespace std;" in C++
- "int" für Array-Indices
- Makros für alles und jedes statt inline-Funktionen und Konstanten
- Nutzung von "int" statt "int32_t" o.ä.
- *NULL
- char x [7]; x [3] = NULL;
- int x = ... ; char lowerByte = ((char*) &x) [0];
- printf ("%d\n", irgendEinPointer);
... sieht man sehr häufig. Das könnte man gerne besser lehren...

Wegen C++: Das lernt man am Besten mit einem guten Buch. Viele Bücher 
sind schlecht. Hier ist eine Liste guter Bücher:
https://stackoverflow.com/a/388282

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Nutzung von "int" statt "int32_t"

Kann aber gut und gern sinnvoll sein.  int32_t schreibt halt zwingend
vor, dass es genau 32 Bits sein müssen – auch dann, wenn das für
irgendeine Architektur vielleicht gerade nicht optimal ist.

int_fast32_t würde sagen: „nimm mindestens 32 Bits, aber es soll schnell
sein“.  Das ist das, was man meistens brauchen würde an dieser Stelle.

"int" allein hat aber eine hinreichend garantierte Minimalgröße, dass
es für viele Fälle genügt, und die Annahme ist, dass es für eine
bestimmte Architektur die Größe ist, die auf dieser Maschine am
besten verarbeitbar ist (auf einem AVR sind es daher 16 Bits, auf
einem ARM 32, auf anderen können es auch 64 sein).

Aber ich gebe dir Recht: genau solche Abwägungen müsste man natürlich
besser unter die Leute bringen.

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> Kann aber gut und gern sinnvoll sein

Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte 
wissen wann es sinnvoll ist und wann nicht ist. Statt int würde ich aber 
auch lieber int_least16_t schreiben, hat die gleiche Bedeutung aber es 
zeigt klarer was man haben will.

von Dr. Sommer (Gast)


Lesenswert?

Possetitjel schrieb:
>> Für andere aber nicht. Ich merke deutlich die Unterschiede
>> im Denken bei der Zusammenarbeit mit Ingenieuren.
>
> Nur interessehalber: Welche sind das? Bzw. wie zeigen sie
> sich?

Schwierig in Worte zu fassen. Ein Versuch:
- Ingenieure denken in Bauplänen und Komponenten. Alles was nicht als 
Blockdiagramm darstellbar ist ist für den Ing kaum fassbar. Software 
lässt sich aber nur sehr begrenzt so darstellen, oder immer nur eine 
Sichtweise davon...
- Wenn für den Ing zwei Komponenten irgendwie zusammenpassen, ist alles 
ok. Aus Software-Sicht ist die Kombination beliebiger Teile oft nicht 
sinnvoll, was nicht so leicht vermittelbar ist. Bspw. einen ESP32 an 
einem R-PI mit Linux anzuschließen ist nur auf den 3. Blick "irgendwie 
komisch".
- Hardware lässt sich gut wasserfall-artig entwickeln, von Anforderungen 
bis Tests. Ist bei Software oft weniger angemessen, und agile Prozesse 
passen ggf. nicht gut in ein Ingenieurs-Unternehmen. Software ist auch 
nie wirklich fertig.
- Für Ing.-Arbeiten lassen sich wunderbar ToDo-Listen und 
Arbeitsvorgänge planen - à la der Abteilungsleiter plant wer was wann 
macht - das ist bei Software und den komplexen Abhängigkeiten schwierig.
- Ing.-Arbeit ist oft "richtige Arbeit", die man Schritt für Schritt 
abarbeiten kann. SW-Entwicklung ist oft ein kreativer Prozess mit 
ungewissem Weg, Dauer und Ende.
- Ings haben oft kaum das Deployment/Inbetriebnahme im Blick. Als 
Embedded-Entwickler darf man sich dann mit Platinen befassen, die keine 
Test-LED's/Taster, Testpunkte, komische JTAG-Stecker, allgemein winzige 
unpraktische Stecker haben. Der klitzekleine "SW-Entwicklung"-Schritt 
zwischen Löten und Einbauen wird da gern übersehen.
- Ings haben nicht so das Gefühl für Fehlersuche. Wenn da was nicht 
klappt stehen die oft ratlos da. Als Informatiker hat man mehr so das 
Verlangen möglichst viele Informationen zu sammeln um das Problem 
einzugrenzen, so klärt sich schon vieles.

Das soll alles keine Beleidigung sein, sind nur ein paar Erfahrungen. 
Ings können haben bestimmt auch genug Probleme mit Informatikern. 
Natürlich hängt das alles stark vom Einzelfall ab, und die Probleme 
lassen sich mit Kommunikation und Organisation angehen. Aber dran denken 
muss man...

von Jobst Q. (joquis)


Lesenswert?

Dr. Sommer schrieb:
> Funktioniert nicht mit Strings die 0-Bytes enthalten

Markus F. schrieb:
>> ... Strings die 0-Bytes enthalten...
>
> das ist für C-Programmierer ein Oxymoron.

Ist es nicht. Jeder C-String enthält ein 0-Byte, selbst ein leerer 
String.
Aber eben nur eins.

Ein Byte-Array, das mehrere 0-Bytes oder auch keins enthalten kann, ist 
eben kein String, sondern ein Mem-Block. Dazu gibt es eigene Funktionen.

Die haben aber den Nachteil, dass sie zwingend als zweiten Parameter 
eine Länge brauchen, während zum Lesen eines Strings ein Pointer genügt. 
Zum Schreiben von Strings ist ein zweiter Pointer als Begrenzung oder 
die Restlänge des Puffers sinnvoll.

Da Strings die Aufgabe haben, sowohl von Menschen als auch von Maschinen 
lesbar und schreibbar zu sein, ist die Sonderfunktion des 0-Bytes keine 
Beeinträchtigung.

von Possetitjel (Gast)


Lesenswert?

Yalu X. schrieb:

> Ich habe mir die Mühe gemacht, deinen ellenlangen Beitrag
> von oben durchzulesen,

Ohh. Vielen Dank.

> jetzt musst du dasselbe auch mit meinem tun ;-)

Sehr gern.


> Wenn ich dich richtig verstehe, versucht du, sämtliche
> Eigenschaften von Programmiersprachen auf Automaten
> abzubilden, um sie dadurch besser zu verstehen.

Ähh... Nein.

Ich habe die Beobachtung gemacht, dass BESTIMMTE Eigen-
schaften von Programmiersprachen für mich sehr viel
leichter verständlich werden, wenn ich sie auf (endliche)
Automaten abbilde.

Das Verständnis fällt mir SO viel leichter, dass ich
mich ernsthaft frage, warum die übliche Darstellung
auf eine so hirnrissig komplizierte Weise erfolgt.

> Kann es sein, dass du dich damit selber blockierst und
> so somit genau das Gegenteil von dem erreichst, was du
> eigentlich anstrebst?

Sicher kann das sein -- aber erlaube die Gegenfrage:
Was bringt Dich auf den Verdacht, es sei so?


> Was du in deinen Beispielen mittels Automaten beschreibst,
> sind im Wesentlichen Ablaufstrukturen (Sprünge, Unter-
> programmaufrufe, Objekte mit Memberfunktionen, Parallelität
> usw.).

Hmm, ja.

> Im Gegensatz zu Assembler und Ur-Fortran zeichnen sich
> moderne Sprachen aber durch weit mehr als nur die von
> ihnen unterstützten Ablaufstrukturen aus, als da wären:
>
> - Datentypen (numerisch, textuell, primitiv, zusammengesetzt,
>   ...)
>
> - Typsysteme (stark, schwach, statisch, dynamisch, flach,
>   hierarchisch, ...)
>
> - Möglichkeiten der Metaprogrammierung (Lisp-Makros,
>   C++-Templates, ...)
>
> - u.v.m.

"If it's not broken, don't fix it."

Warum sollte ich Dinge umdeuten, mit denen ich in der
traditionellen Formulierung keine Verständnisprobleme
habe?

Nehmen wir die Datentypen: Ich habe da nie tiefer drüber
nachgedacht, aber man kennt es ja aus der Physik, dass eine
physikalische Größe aus Zahlenwert und Einheit besteht, und
dass man als Folge dessen nur Größen rechnerisch verknüpfen
darf, deren Einheiten kompatibel sind. (Dafür gibt es sogar
eine m.o.w. algebraische Begründung.)
Das ist ja letztlich genau das, was auch Datentypen im
Computer bewirken; das ist eine vertraute Geschichte.

Warum sollte ich das auf Krampf umdeuten wollen?

[...]
> Ich habe deswegen lange nach einem besseren Ersatz für
> diese Maschinchen gesucht und schließlich auch gefunden:
>
>   Mathematische Modelle

Ich verstehe die Worte, nicht aber ihren Sinn: Ein Automat
IST doch (auch bzw. primär) ein mathematisches Modell --
nämlich ein Quintupel (X, Y, Z, f, g) mit bestimmten Eigen-
schaften.
Nur hat dieses mathematische Modell den großen Vorzug, dass
ich sehr einfache elektronische Realisierungen für wenige
Cent bei der eingetragenen Kauffrau in Sande kaufen kann.

Wann hat man dieses Privileg schon mal: Anschauungsmodelle
für mathematische Konzepte, die man im Bastlerladen kaufen
kann?

Und ein weiterer Vorzug: Mir als E-Techniker ist das Modell
des endlichen Automaten vertraut -- also warum sollte ich
dieses Wissen nicht in Anschlag bringen, wenn es möglich
ist?

> Endgültig die Augen aufgegangen sind mir, als ich begann,
> mich mit funktionaler Programmierung zu beschäftigen. In
> der reinen FP gibt es weder Abläufe noch Zustände, weswegen
> die Vorstellung von Maschinchen schon per se zu nichts
> führen kann.

Ich bin... verwirrt.

> Mit mathematische Modellen hingegen kann man einige Dinge
> tun, die mit den Maschinchen in meinem Kopf kaum möglich
> sind:

Wahrscheinlich missverstehe ich Deine Intention gründlich,
aber was ist Automatentheorie für Dich? Sowas wie die
Backförmchen für die Kindergartenkinder? Cargo-Mathematik
(--> Cargo-Kult) für Debile (=Elektrotechniker)?


[...]
> Immer wieder fallen mir bei schwierigen Problemen weitere
> Wege ein, die zwar abstrakt anmuten, aber letztendlich
> dazu geeignet sind, hinderliche Knoten in Gehirnwindungen
> zu lösen und damit die Problemstellung zu vereinfachen.

Naja... ist das nicht die Stärke jeder guten, verständigen
Abstraktion?

"Es gibt nichts praktischeres als eine gute Theorie."


> Und das Beste dabei: Die Erkenntnisse, die man dabei gewinnt,
> lassen sich nicht nur auf die FP, sondern mit leichten
> Einschränkungen auch auf die klassische Programmierung in
> C oder C++ anwenden.

Ich weiss immer noch nicht, worauf Du mit der funktionalen
Programmierung hinauswillst.

Die Sache ist faszinierend, ja -- unter anderem deshalb,
weil sie (genau wie die Deutung durch endliche Automaten)
ohne "Algorithmen" und die dadurch entstehenden "parasitären"
Zustände auskommt.
Vielleicht mache ich einen Fehler, aber ich sehe noch nicht,
wie mir die FP z.B. im Kontext der OOP helfen sollte.


> Was ich damit ausdrücken möchte: Die Informatiker, deren
> Geschwurbel du nicht verstehst, sind entweder tatsächlich
> Dummschwätzer oder Angeber, oder aber sie denken in Modellen,
> die sie persönlich zwar befähigen, selbst schwierigste
> Probleme zu lösen, die sich aber leider nicht in deine Welt
> der Automaten übersetzen lassen.

Nein, weder -- noch. Völlig anders.

Ich habe kein grundsätzliches Problem mit der theoretischen
Informatik. Das ist halt mathematischer Stoff genau wie
Feldtheorie, Numerik oder Algebra. Es ist hart, sich den
Stoff zu erarbeiten, aber es lohnt sich in der Regel, weil
man sich dauerhaftes Hintergrundwissen aufbaut. Das Hinter-
grundwissen ist zwar interessant, aber kurzfristig nicht
unmittelbar praktisch anwendbar.

Unmittelbar praktisch anwendbar wäre die zuverlässige
Beherrschung einer Programmiersprache. Leider habe ich ein
MASSIVES Problem mit den meisten Büchern, die mir eine
Programmiersprache beibringen wollen. Die Darstellungen
kleben dermaßen schrecklich an syntaktischen Details und
geben so wenig Einblick in die hinterliegenden Konzepte,
dass ich i.d.R. nach wenigen Seiten einen Wutanfall
bekomme.

Wenn ich von Digitaltechnik keine Ahnung hätte, würde ich
mich schätzungsweise deprimiert und demütig in die Ecke
setzen und mich schämen, weil ich so dumm bin.

Sehr zum Nachteil meiner Mitmenschen HABE ich aber gewisse
Grundkenntnisse in Automatentheorie. Gestützt auf diese
Kenntnisse fährt mir ein ums andere Mal in die Nase, dass
die angewandten Informatiker, die die Bücher verfasst
haben, KONSEQUENT alle die schönen, einfachen, klaren
theoretischen Modelle ignorieren, die ihre Fachkollegen
aus der theoretischen Informatik und der Digitaltechnik
bereitgestellt haben.

Man kann (nicht alle, aber) viele Sachverhalte, mit denen
übliche Programmiersprachen hantieren, klar und verständlich
in den Begriffen der Automatentheorie darstellen -- ABER
DAS WIRD NICHT GEMACHT!

Wozu wurden die Begriffe der Automatentheorie entwickelt,
wenn sie dann nicht bei einer der häufigsten Tätigkeiten
in der Informatikausbildung -- nämlich dem Lehren von
Programmiersprachen -- verwendet werden?

von Roland F. (rhf)


Lesenswert?

Hallo,

Dr. Sommer schrieb:
> Wegen C++: Das lernt man am Besten mit einem guten Buch. Viele Bücher
> sind schlecht. Hier ist eine Liste guter Bücher:
> https://stackoverflow.com/a/388282

Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist 
nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den 
neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.
Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich 
feststellen, das sich die entsprechende Literatur in syntaktischen 
Einzelheiten der Programmiersprache verliert, anstatt erst mal 
grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten 
Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht 
es da genau wie Possetitjel,

Zitat:
> Leider habe ich einMASSIVES Problem mit den meisten Büchern, die mir
> eine Programmiersprache beibringen wollen. Die Darstellungen kleben
> dermaßen schrecklich an syntaktischen Details und geben so wenig
> Einblick in die hinterliegenden Konzepte, dass ich i.d.R. nach wenigen
> Seiten einen Wutanfall bekomme.

rhf

von Wilhelm M. (wimalopaan)


Lesenswert?

Roland F. schrieb:

> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist
> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den
> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.
> Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich
> feststellen, das sich die entsprechende Literatur in syntaktischen
> Einzelheiten der Programmiersprache verliert, anstatt erst mal
> grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten
> Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht
> es da genau wie Possetitjel,

Die Menge der primitiven DT ist ja doch sehr einfach und gering, dann 
gibt es noch die abgeleiteten Typen und die modifier 
const/volatile/mutable, s.a.:

http://en.cppreference.com/w/cpp/language/type

Nur diese Typen haben einen direkten Bezug zu Sprachkonstrukten.

Oder meinst Du die Templates der libstdc++?

von mh (Gast)


Lesenswert?

Roland F. schrieb:
> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist
> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den
> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.
> Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich
> feststellen, das sich die entsprechende Literatur in syntaktischen
> Einzelheiten der Programmiersprache verliert, anstatt erst mal
> grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten
> Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht
> es da genau wie Possetitjel,

Das kann man meistens nicht den Büchern/Autoren anlasten. Es ist z.B. 
schwer die objektorientierten Features von C++ zu verstehen, ohne 
grundlegendes OOP Kenntnisse. Es ist allerdings nicht sinnvoll den 
kompletten Inhalt eines C++ und eines OOP Lehrbuch in ein einzelnes Buch 
zu packen, denn niemand möchte für Grundlangen ein 3000 Seiten 200€ Buch 
haben. Und was würde man dann mit den ganzen anderen Themen wie 
prozeduale, funktionale und generische Programmierung machen? Alles in 
ein Buch packen? Es müssen also immer mehrere Bücher benutzt werden.

von Ach ja ;) (Gast)


Lesenswert?

mh schrieb:
> Roland F. schrieb:
>> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist
>> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den
>> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.

> Das kann man meistens nicht den Büchern/Autoren anlasten. Es ist z.B.
> schwer die objektorientierten Features von C++ zu verstehen, ohne
> grundlegendes OOP Kenntnisse.

Das hat sich C++ nun mal leider selber zu eigen gemacht. C# 
beispielsweise hat den Vererbungsrattenschwanz auf ein notwendiges Maß 
eingeschränkt und es scheint auch zu gehen. Wenn C# kritisiert wird, 
dann stets z.B. weil man der automatisierten, hausinternen 
Daten-Müllabfuhr genannt GC misstraut bzw. sie für wenig performant 
hält, aber nicht, weil man wie bei C++ rückwirkend bis zu August dem 
Starken noch Erbansprüche seiner Klasse beifügen kann.

C++ ist für viele anscheinend nur dann erträglich und alltagstauglich, 
indem sie es als besseres C verwenden. Das wird auch immer wieder 
zugegeben und ist ja auch nicht verwerflich, wirft aber halt Fragen auf 
bezüglich des Konzepts und der daraus abgeleiteten Lerntauglichkeit 
dieser Sprache. Und die vielen recht oberflächlichen C++ Bücher 
untermauern letztlich doch diesen Eindruck. Auch den Autoren dieser 
Bücher scheint es offensichtlich große Mühe zu bereiten, die wahren 
Vorteile von C++ dem geneigten Leser verständlich zu vermitteln.

von Ach ja ;) (Gast)


Lesenswert?

Korrektur, muss heißen

" ... aber nicht, weil man NICHT wie bei C++ rückwirkend bis zu August 
dem
Starken noch Erbansprüche seiner Klasse beifügen kann."

von Yalu X. (yalu) (Moderator)


Lesenswert?

Possetitjel schrieb:
>> Wenn ich dich richtig verstehe, versucht du, sämtliche
>> Eigenschaften von Programmiersprachen auf Automaten
>> abzubilden, um sie dadurch besser zu verstehen.
>
> Ähh... Nein.

Ok, dann habe ich dich wahrscheinlich komplett missverstanden.

> Ich habe die Beobachtung gemacht, dass BESTIMMTE Eigen-
> schaften von Programmiersprachen für mich sehr viel
> leichter verständlich werden, wenn ich sie auf (endliche)
> Automaten abbilde.

Mir persönlich geht es eher so:

Diejenigen Aspekte von Programmiersprachen, für die es mir gelingt, sie
auf endliche Automaten abzubilden, verstehe ich auch ohne diese.
Deswegen hat es mich zunächst etwas überrascht, dass das bei dir anders
ist. Aber da hat wohl jeder seine eigene Denkweise, mit der er am besten
klar kommt, was ja vollkommen in Ordnung ist.

> Das Verständnis fällt mir SO viel leichter, dass ich
> mich ernsthaft frage, warum die übliche Darstellung
> auf eine so hirnrissig komplizierte Weise erfolgt.

Es könnte sein, dass es relativ wenig Leute gibt, die in diesem
Zusammenhang in Automaten denken. Deswegen gibt es ebenso wenige, die
dir etwas in deiner Sprache bzw. Denkweise erklären können.

>> Im Gegensatz zu Assembler und Ur-Fortran zeichnen sich
>> moderne Sprachen aber durch weit mehr als nur die von
>> ihnen unterstützten Ablaufstrukturen aus, als da wären:
>>
>> - Datentypen (numerisch, textuell, primitiv, zusammengesetzt,
>>   ...)
>>
>> - Typsysteme (stark, schwach, statisch, dynamisch, flach,
>>   hierarchisch, ...)
>>
>> - Möglichkeiten der Metaprogrammierung (Lisp-Makros,
>>   C++-Templates, ...)
>>
>> - u.v.m.
>
> "If it's not broken, don't fix it."
>
> Warum sollte ich Dinge umdeuten, mit denen ich in der
> traditionellen Formulierung keine Verständnisprobleme
> habe?

Jetzt verstehe ich gar nichts mehr :)

Wenn du nicht nur die Ablaufstrukturen verstanden hast, sondern auch
abstraktere Dinge wie die oben genannten, dann bist du ja fast schon auf
einer Ebene mit Wilhelm, und ich frage mich, was du denn noch nicht
verstanden hast. Vielleicht nennst du mal ein konkretes Beispiel, dann
können wir darüber diskutieren, mit welchen Hilfsmitteln man das am
besten erklären kann.

>> Ich habe deswegen lange nach einem besseren Ersatz für
>> diese Maschinchen gesucht und schließlich auch gefunden:
>>
>>   Mathematische Modelle
>
> Ich verstehe die Worte, nicht aber ihren Sinn: Ein Automat
> IST doch (auch bzw. primär) ein mathematisches Modell --
> nämlich ein Quintupel (X, Y, Z, f, g) mit bestimmten Eigen-
> schaften.

Es ist ein mathematisches Modell, das zur Beschreibung bestimmter
Sachvehalte sehr gut taugt, für andere weniger gut und für wieder andere
überhaupt nicht.

> Nur hat dieses mathematische Modell den großen Vorzug, dass
> ich sehr einfache elektronische Realisierungen für wenige
> Cent bei der eingetragenen Kauffrau in Sande kaufen kann.

Du baust doch deine Automaten zur Erklärung von Programmieraspekten doch
nicht etwa in realer Elektronik auf? =8o

> Und ein weiterer Vorzug: Mir als E-Techniker ist das Modell
> des endlichen Automaten vertraut -- also warum sollte ich
> dieses Wissen nicht in Anschlag bringen, wenn es möglich
> ist?

Wenn sie dir weiterhelfen, dann ist das in Ordnung. Mir (und
offensichtlich auch Wilhelm) helfen sie nicht weiter. Das ist für mich
ebenfalls in Ordnung, solange ich einen anderen Weg finde, etwas zu
verstehen :)

>> Endgültig die Augen aufgegangen sind mir, als ich begann,
>> mich mit funktionaler Programmierung zu beschäftigen. In
>> der reinen FP gibt es weder Abläufe noch Zustände, weswegen
>> die Vorstellung von Maschinchen schon per se zu nichts
>> führen kann.
>
> Ich bin... verwirrt.

Ich anfangs auch ;-)

> Wahrscheinlich missverstehe ich Deine Intention gründlich,
> aber was ist Automatentheorie für Dich? Sowas wie die
> Backförmchen für die Kindergartenkinder? Cargo-Mathematik
> (--> Cargo-Kult) für Debile (=Elektrotechniker)?

Nein, überhaupt nicht. Ich benutze Automatentheorie durchaus, bspw. als
Hilfsmittel für den Entwurf von Digitalschaltungen. Automaten ohne die
Theorie setze ich manchmal als Entwurfsmuster in der Softwareentwicklung
ein.

> Ich weiss immer noch nicht, worauf Du mit der funktionalen
> Programmierung hinauswillst.

Sie hat bei mir dazu geführt, bei der Softwareentwicklung weniger in
Schritt-für-Schritt-Abläufen, sondern mehr in mathematischen Funktionen
zu denken. Das heißt aber nicht, dass ich das "Schrittdenken" komplett
aufgegeben habe, aber ich beschränke es auf diejenigen Anwendungen, die
zu deren Natur es gut passt.

Beispiele:

- Eine Waschmaschinensteuerung schaltet schrittweise, abhängig von der
  Zeit und von Sensorinformationen verschiedene Aktoren (Ventile, Pumpen
  Trommelantrieb) ein und aus. Dafür ist das Schrittdenken und die
  Formalisierung mit Automaten sehr gut geignet.

- Ein Sortieralgorithmus wird zwar vom Prozessor ebenfalls schrittweise
  ausgeführt, von der Natur der Sache ist er aber eine mathematische
  Funktion, deren Argument eine unsortierte, und deren Funktionswert die
  sortierte Liste ist. Einen solchen Algorithmus mittels Automaten zu
  beschreiben oder seine Ausführung in einem Debugger Schritt für
  Schritt mitzuverfolgen, ist viel Arbeit und bringt für mich keinerlei
  Nutzen.

> Die Sache ist faszinierend, ja -- unter anderem deshalb,
> weil sie (genau wie die Deutung durch endliche Automaten)
> ohne "Algorithmen" und die dadurch entstehenden "parasitären"
> Zustände auskommt.
> Vielleicht mache ich einen Fehler, aber ich sehe noch nicht,
> wie mir die FP z.B. im Kontext der OOP helfen sollte.

So richtig gesehen habe ich das auch erst, als ich es gemacht habe. So
wie einer, der in der OOP zu Hause ist, auch gewöhnliche C-Programme
anders strukturieren wird, als einer, der von klassischem Basic kommt,
wird der C-Code von einem FPler noch einmal anders aussehen. In beiden
Fällen wird der resultierende C-Code an Verständlichkeit, Wartbarkeit
und Eleganz gewinnen.

Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.
darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,
C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und
funktionale Elemente in sich vereinen. Da sie dem Programmierer kein
bestimmtes Paradigma aufzwingen, ist mit ihnen ein sanfter Einstig in
die jeweiligen Paradigmen möglich.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.
> darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,
> C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und
> funktionale Elemente in sich vereinen.

Und als Zusatz bzw. als das ganz Besondere (meiner Meinung nach) die 
generische Programmierung, die sich wunderbar mit FP zusammenfügt. Ich 
gebe zu, über die syntaktische Ausgestaltung bei C++ kann man geteilter 
Meinung sein ;-) Durch Gewohnheit stört es mich nicht mehr.

> Da  sie dem Programmierer kein
> bestimmtes Paradigma aufzwingen, ist mit ihnen ein sanfter Einstig in
> die jeweiligen Paradigmen möglich.

Und das sehe ich als die ganz große Stärke gerade von C++ an. Dadurch 
kann man m.E. eine sehr große Expressivität im Code erreichen.

von Mark B. (markbrandis)


Lesenswert?

Dr. Sommer schrieb:
> Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte
> wissen wann es sinnvoll ist und wann nicht ist.

Toll finde ich die Programmierer, die für eine Masse oder für ein 
Volumen int verwenden (in C oder C++).

:-(

von Wilhelm M. (wimalopaan)


Lesenswert?

Mark B. schrieb:
> Dr. Sommer schrieb:
>> Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte
>> wissen wann es sinnvoll ist und wann nicht ist.
>
> Toll finde ich die Programmierer, die für eine Masse oder für ein
> Volumen int verwenden (in C oder C++).

Ach, die Diskussion führe ich hier doch regelmäßig! Alles ist ein int, 
und wenn nicht, dann ein String.

: Bearbeitet durch User
von Alexander T. (Firma: Arge f. t. abgeh. Technologie) (atat)


Lesenswert?

Markus F. schrieb:
> Dr. Sommer schrieb:
>> ... Strings die 0-Bytes enthalten...
>
> das ist für C-Programmierer ein Oxymoron.

Im Gegentum: Ein C-String, der am Ende kein NUL enthält, ist kaputt. 
Also ist's eher eine Tautologie.

von Dr. Sommer (Gast)


Lesenswert?

Alexander T. schrieb:
> Im Gegentum: Ein C-String, der am Ende kein NUL enthält, ist kaputt.
> Also ist's eher eine Tautologie

Und was ist NUL? Hoffentlich nicht NULL?

Ersetzt einfach "String" durch Byte-Array, dann passt es wieder. Oft 
genug hat man Byte-Arrays die 0-Bytes enthalten können.

Lustig wird sowas:
1
std::string fileName = getUserInput();
2
if(fileName == "geheim.txt")
3
  Error ("Permission denied");
4
fopen (fileName.c_str (), "r");
Wenn der User jetzt "geheim.txt\0bla" eingibt, greift die Sicherheits 
Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld? 
Sowas ähnliches ist/war eine Sucherheitslücke in PHP.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>
>> Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.
>> darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,
>> C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und
>> funktionale Elemente in sich vereinen.
>
> Und als Zusatz bzw. als das ganz Besondere (meiner Meinung nach) die
> generische Programmierung, die sich wunderbar mit FP zusammenfügt. Ich
> gebe zu, über die syntaktische Ausgestaltung bei C++ kann man geteilter
> Meinung sein ;-)

Am besten ist es, wenn man die Generizität für jede Funktion sozusagen
gratis mit dazu bekommt, ohne dass man dazu eine spezielle Syntax
bemühen muss. Haskell und F# zeigen, wie's geht.

Eine Funktion, die die Summe einer Zahlenfolge berechnet, könnte in
Haskell bspw. so definiert werden:

1
mySum = foldl' (+) 0

foldl' ist dabei eine Bibliotheksfunktion, (+) die Funktion, die auf die
Elemente der Folge angewandt werden soll, und 0 der Initialwert für
die Aufsummierung.

Der Aufruf

1
mySum [1, 2, 5]

liefert das Resultat 8. Die Funktion erlaubt dabei beliebige faltbare
Argumente (List, Array, Set usw.) mit beliebigen numerischen Elementen
(Integer, Rational, Double, Complex Double usw.).

So leicht kann das Schreiben von wiederverwendbarem Code gehen :)

von Jobst Q. (joquis)


Lesenswert?

Dr. Sommer schrieb:
> Lustig wird sowas:std::string fileName = getUserInput();
> if(fileName == "geheim.txt")
>   Error ("Permission denied");
> fopen (fileName.c_str (), "r");Wenn der User jetzt "geheim.txt\0bla"
> eingibt, greift die Sicherheits
> Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld?
> Sowas ähnliches ist/war eine Sucherheitslücke in PHP.

Mit purem C wäre das nicht passiert.

Der Murks liegt also  bei getUserInput() und der Sicherheitsprüfung, für 
die die Konstrukteure von std::string verantwortlich sind.

: Bearbeitet durch User
von Keiner N. (nichtgast)


Lesenswert?

Dr. Sommer schrieb:

> Lustig wird sowas:
>
1
std::string fileName = getUserInput();
2
> if(fileName == "geheim.txt")
3
>   Error ("Permission denied");
4
> fopen (fileName.c_str (), "r");
> Wenn der User jetzt "geheim.txt\0bla" eingibt, greift die Sicherheits
> Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld?
> Sowas ähnliches ist/war eine Sucherheitslücke in PHP.

Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen, 
wenn es gar nicht anders geht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Statt int würde ich aber auch lieber int_least16_t schreiben, hat die
> gleiche Bedeutung aber es zeigt klarer was man haben will.

int_fast16_t :)

int_least16_t würde ggf. auf Kosten von Rechenzeit (Bitmaskierung)
verlangen, dass es möglichst 16 Bit sind, dürfen nur dann mehr sein,
wenn die Architektur gar nicht mit 16-Bit-Einheiten umgehen kann.

von Alex D. (allu)


Lesenswert?

Zur ursprünglichen Frage:

Mark W. schrieb:
> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
Nein, nie.

Mark W. schrieb:
> Oder geht das gar nicht?
Ja!

Erst die Aufgabe analysieren und dafür großzügig Zeit nehmen, dann das 
Programm (gilt auch für Hardware) entwickeln und siehe da, man spart 
insgesamt gesehen Zeit!

von Dr. Sommer (Gast)


Lesenswert?

Keiner N. schrieb:
> Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen,
> wenn es gar nicht anders geht.

Leider sind die meisten Kernel in C geschrieben, und syscalls wie open 
nutzen 0-terminierte Strings, auch wenn man sie direkt aus C++ aus 
aufruft.

Jobst Q. schrieb:
> Mit purem C wäre das nicht passiert.

Mit purem C++ auch nicht. Leider ist POSIX C-orientiert...

Jobst Q. schrieb:
> für die die Konstrukteure von std::string verantwortlich sind.

Die Entwickler von std::string können wohl kaum was für diese Prüfung. 
Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer 
denkt schon an sowas.

von Jobst Q. (joquis)


Lesenswert?

Keiner N. schrieb:
> Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen,
> wenn es gar nicht anders geht.

C++ ist eine Erweiterung von C. Das ist ja auch der Vorteil gegenüber 
anderen objektorientierten Sprachen. Also sollte es kompatibel mit C 
sein.

Eine Neudefinition von String von einer Zeichenfolge, die mit dem 
Null-Byte abgeschlossen wird, zu einem beliebigen Byte-Array ist ein 
schwerwiegender Konstruktionsfehler.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dr. Sommer schrieb:
> Die Entwickler von std::string können wohl kaum was für diese Prüfung.
> Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer
> denkt schon an sowas.

Ich wollte gerade schreiben, dass die Prüfung auf '\0'-Zeichen innerhalb
des Dateinamens Aufgabe von [i][o]fstream::open(string &, ...) wäre,
denn genau hier geschieht die Umwandlung eines std::string-Dateinamens
in einen POSIX-, d.h. C-Dateinamen, und der Nutzer solcher High-Level-
Bibliotheksfunktionen sollte sich nicht darum kümmern müssen, ob sein
Betriebssystem POSIX-konform ist oder nicht.

Allerdings hat mich das ISO-Dokument eines Besseren belehrt:

1
   void open(const string& s, ios_base::openmode mode = ios_base::in);
2
   void open(const filesystem::path& s, ios_base::openmode mode = ios_base::in);
3
4
   Effects: Calls open(s.c_str(), mode).

Daraus geht hervor, dass der Dateiname am ersten '\0'-Zeichen unabhängig
vom Betriebssystem immer abgeschnitten wird und sogar werden muss. Wer
darauf reinfällt, hat halt vorher nicht genau genug nachgelesen ;-)

Vor C++11 gab es die open()-Variante mit dem std::string-Dateinamen noch
nicht, weswegen der Programmierer die c_str()-Konvertierung selber
hinschreiben musste, und somit eher auf das Problem aufmerksam wurde.

Die mit C++11 eingeführte Falle hätte man anständigerweise entschärfen
können, indem man in open() eine Prüfung auf '\0'-Zeichen eingebaut
hätte. Man hat es nicht getan, was wieder einmal bestätigt, dass die
Programmiererei kein Ponyhof ist, sondern nur der des Lesens Mächtige
erfolgreich sein kann  ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Eine Funktion, die die Summe einer Zahlenfolge berechnet, könnte in
> Haskell bspw. so definiert werden:
>
>
>
1
> mySum = foldl' (+) 0
2
>
>
> foldl' ist dabei eine Bibliotheksfunktion, (+) die Funktion, die auf die
> Elemente der Folge angewandt werden soll, und 0 der Initialwert für
> die Aufsummierung.
>
> Der Aufruf
>
>
>
1
> mySum [1, 2, 5]
2
>
>
> liefert das Resultat 8. Die Funktion erlaubt dabei beliebige faltbare
> Argumente (List, Array, Set usw.) mit beliebigen numerischen Elementen
> (Integer, Rational, Double, Complex Double usw.).
>
> So leicht kann das Schreiben von wiederverwendbarem Code gehen :)

In C++:
1
    auto mysum = [](auto... vv){return (vv + ... + 0);};
2
    result = mysum(1, 2, 5);

Ist allerdings nur statisch.

: Bearbeitet durch User
von Roland F. (rhf)


Lesenswert?

Hallo,

mh schrieb:
> Es ist allerdings nicht sinnvoll den kompletten Inhalt eines C++ und
> eines OOP Lehrbuch in ein einzelnes Buch zu packen, denn niemand möchte
> für Grundlangen ein 3000 Seiten 200€ Buch haben.

Ja, das ist richtig. Aber das Buch "Einführung in die Programmierung mit 
C++" von Bjarne Stroustrup hat z.B. 1224 Seiten und trotzdem gibt es 
keinen Platz für einen Überblick über die Konzepte, die hinter C++ 
stehen.
Dafür findet man im Kapitel 1 unter 1.5 "Computer sind allgegenwärtig" 
eine _9_-seitige Aufstellung über Lebensbereiche, in denen Computer eine 
wichtige Rolle spielen (das angeeignete Wissen wird dann mit Frage wie 
"Wo spielt Software eine wichtige Rolle?. Nennen Sie einige Beispiele" 
abgefragt. Mal ehrlich: was soll das?). Wenn für "sowas" Platz ist, dann 
sollte es doch ein leichtes sein, auf 20-30 Seiten die Ideen, die hinter 
C++ stehen zu beschreiben.

> Und was würde man dann mit den ganzen anderen Themen wie
> prozeduale, funktionale und generische Programmierung machen? Alles in
> ein Buch packen?

Da stellt sich die Frage was die Aufgabe eines 
Programmiersprachenlehrbuches ist. Wenn die Darstellung der Konzepte 
nicht dazu gehört, reicht ja eigentlich auch die Sprachreferenz der 
aktuellen Version.

> Es müssen also immer mehrere Bücher benutzt werden.

Darauf wird es wohl hinauslaufen. Das erinnert mich allerdings an eine 
Aussage eines Lehrers bezüglich des Lernens von Fremdsprachen. Er war 
der Meinung, das man (europäische) Sprachen viel einfacher erlernen 
könnte wenn man vorher Latein gelernt hätte. Da ist sicherlich auch was 
dran, aber wenn jemand nur Französisch lernen will, kann man ja nicht 
sagen "dann mach erst mal das große Latinum, danach ist Französisch ganz 
einfach".

Vielleicht hast du aber recht und es geht wirklich nicht anders. 
Allerdings stellt sich dann die Frage ob die momentan aktuellen 
Programmiersprachenkonzepte wirklich sinnvoll sind. In Anbetracht der 
der immer größer werdenden Wichtigkeit Software erstellen zu können, 
kann man nicht erwarten das jeder zukünftige Programmierer über intimste 
Informatikkenntnisse verfügt.

rhf

von TriHexagon (Gast)


Lesenswert?

Roland F. schrieb:
> Ja, das ist richtig. Aber das Buch "Einführung in die Programmierung mit
> C++" von Bjarne Stroustrup hat z.B. 1224 Seiten und trotzdem gibt es
> keinen Platz für einen Überblick über die Konzepte, die hinter C++
> stehen.
> Dafür findet man im Kapitel 1 unter 1.5 "Computer sind allgegenwärtig"
> eine _9_-seitige Aufstellung über Lebensbereiche, in denen Computer eine
> wichtige Rolle spielen (das angeeignete Wissen wird dann mit Frage wie
> "Wo spielt Software eine wichtige Rolle?. Nennen Sie einige Beispiele"
> abgefragt. Mal ehrlich: was soll das?).

Das ist natürlich unverständlich. Allerdings ist das Buch wohl auch 
einfach hauptsächlich für Studenten und Dozenten geschrieben. Sieht für 
mich jedenfalls so aus.

Roland F. schrieb:
> Wenn für "sowas" Platz ist, dann
> sollte es doch ein leichtes sein, auf 20-30 Seiten die Ideen, die hinter
> C++ stehen zu beschreiben.

Das wird nicht funktionieren, einfach weil C++ eine Multiparadigma 
Sprache ist. Da braucht es dann schon ein paar Seiten mehr, um alle zu 
behandeln.

Roland F. schrieb:
> Vielleicht hast du aber recht und es geht wirklich nicht anders.
> Allerdings stellt sich dann die Frage ob die momentan aktuellen
> Programmiersprachenkonzepte wirklich sinnvoll sind. In Anbetracht der
> der immer größer werdenden Wichtigkeit Software erstellen zu können,
> kann man nicht erwarten das jeder zukünftige Programmierer über intimste
> Informatikkenntnisse verfügt.

Die Konzepte sind völlig in Ordnung. Aber wenn man zu viel auf einmal 
lernen will, wird man wahrscheinlich daran scheitern. Man muss sich halt 
fragen, ob es sinnvoll ist gleichzeitig das Programmieren zu lernen, 
eine solche mächtige Programmiersprache wie C++ und dann noch ein 
Paradigma wie OOP. Das ist einfach zu viel.

Deshalb würde ich nie und nimmer C++ bei Anfängern für die Lehre 
einsetzen. Das ist eine Sprache, genauso wie C, die ganz klar die 
erfahrenen Nutzer ansprechen will und auf Anfänger keine Rücksicht 
nimmt.

Bei uns im Studium gab es uns die Informatiker und dann die 
Wirtschaftsinformatiker. Wir haben mit C und C++ angefangen, die haben 
ausschließlich Java gemacht. Und wer konnte insgesamt besser mit dem 
Programmieren zurecht (mal diejenigen ausgenommen, die sowie schon 
Programmieren konnten)? Tatsächlich die Wirtschaftsinformatiker, weil 
ihnen die Sprache weniger Steine in den Weg gelegt hatte. Bei uns hatten 
die Studenten schon mit C zu kämpfen (Zeiger, Speicherverwaltung, 
nullterminierte Strings etc.), bei C++ war dann erst recht die Hölle 
los. Auch ist mir aufgefallen, dass die Wirt.Inf. OOP sehr schnell intus 
hatten. Erstens kannten die gar nichts anderes und zweitens ist das 
ganze Thema in Java viel verständlicher (oder die Autoren davon können 
es besser erklären).

Also mein Ratschlag: wer OOP lernen will, sollte einen weiten Bogen um 
C++ machen und lieber C# oder Java dafür hernehmen. Es ist wirklich viel 
einfacher. Danach kann man sich mit C++ befassen. Ich habe das selber so 
gemacht und bin damit sehr gut gefahren, heute ist C++ meine 
Lieblingssprache.

von Jobst Q. (joquis)


Lesenswert?

Dr. Sommer schrieb:
> Die Entwickler von std::string können wohl kaum was für diese Prüfung.
> Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer
> denkt schon an sowas.

Der Murks fängt doch schon damit an, dass es überhaupt möglich ist ein 
Null-Byte inmitten eines Strings einzugeben. Die Funktion getUserInput() 
in deinem Beispiel kenne ich nicht und weiß daher auch nicht,ob die 
Entwickler von std::string dafür verantwortlich sind.

Aber spätestens beim Vergleich mit dem überladenen Operator == hätten 
sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings 
kompatibel sind.

Bei der Entwicklung einer neuen Sprache wäre es egal, ob sie einen 
String als beliebiges Bytearray definieren. Aber als Erweiterung von C 
ist diese Inkompatibilität nicht zu verantworten.

von Dr. Sommer (Gast)


Lesenswert?

Jobst Q. schrieb:
> Die Funktion getUserInput()
> in deinem Beispiel kenne ich nicht und weiß daher auch nicht,ob die
> Entwickler von std::string dafür verantwortlich sind.

Die hab ich mir ausgedacht als Platzhalter für irgendeine Art von 
Eingabe. Könnte z.B. über ein Netzwerk kommen.
BMP-Dateien enthalten z.B. Nullbytes. Wenn man die in einen std::string 
einliest möchte man die erhalten. Wenn man also eine Eingabe/Protokoll 
hat welches allgemein Binär-Daten überträgt, und es auch für Texte 
nutzt, werden 0-Bytes mit übernommen. Dies ist z.B. bei HTTP-Formularen 
der Fall; hier könnte ein Angreifer 0-Bytes mit senden. 0-Bytes in HTTP 
komplett auszuschließen würde aber das Hochladen von BMP-Dateien 
verhindern.
Die 0-Bytes sind auch kein Problem, bis man ein solches Byte-Array an 
eine C/POSIX-Funktion übergibt.

Jobst Q. schrieb:
> Aber spätestens beim Vergleich mit dem überladenen Operator == hätten
> sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings
> kompatibel sind.
Du meinst, es soll immer nur bis zum 0-Byte verglichen werden? Dann wäre 
also std::string("foo\0bar") == "foo" wahr, aber std::string("foo\0bar") 
== std::string("foo") falsch? Auch nicht sehr schön.

Jobst Q. schrieb:
> Aber als Erweiterung von C
> ist diese Inkompatibilität nicht zu verantworten.

std::string ist keine Erweiterung von "const char*" und somit von 
C-Strings!!! std::string ist ein Datentyp für Zeichen-Arrays inklusive 
0-Bytes, wobei ein Zeichen char, wchar, char32_t usw sein kann. Wenn man 
unvorsichtigerweise c_str () aufruft und die Länge nicht mit 
verarbeitet, nutzt man es halt falsch.
C-Strings funktionieren in C++ noch genauso, aber std::string ist eben 
kein Wrapper für C-Strings.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:

> Jobst Q. schrieb:
>> Aber spätestens beim Vergleich mit dem überladenen Operator == hätten
>> sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings
>> kompatibel sind.
> Du meinst, es soll immer nur bis zum 0-Byte verglichen werden? Dann wäre
> also std::string("foo\0bar") == "foo" wahr, aber std::string("foo\0bar")
> == std::string("foo") falsch? Auch nicht sehr schön.

Der Ctor von std::string interpretiert den C-String auch richtig. Also
std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein 
C-String der Länge 3 (per Konvention).

Einen String aus einem std::byte Array zu konstruieren geht nicht.

Der Fehler liegt ggf. schon in dem Netzwerkbeispiel darin, die Bytes vom 
Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Der Ctor von std::string interpretiert den C-String auch richtig. Also
> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein
> C-String der Länge 3 (per Konvention).

Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick 
nutzen um die tatsächliche Länge zu erhalten... Ok, wenn man 0-Bytes 
übergibt muss man die Länge angeben:
1
std::string ("foo\0bar", 7);

Wilhelm M. schrieb:
> die BYtes vom
> Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.
Okay, wie hat man dann Bytes vom Netzwerk interpretiert bevor es 
std::byte gab? byte ist ja auch nur als enum vom typ unsigned char 
definiert. char darf definitiv 0 werden.
In Anbetracht der Tatsache dass die read/write -Funktionen von 
istream/ostream "char*" akzeptieren hätte ich jetzt gedacht, dass man 
char-Arrays, und damit auch std::string, sehr wohl zum Speichern von 
Netzwerkdaten nutzen kann.

von Dr. Sommer (Gast)


Lesenswert?

PS: Das User-Defined Literal "s" für std::string übernimmt 0-Bytes 
korrekt:
1
#include <cstdio>
2
#include <string>
3
#include <iostream>
4
 
5
int main()
6
{
7
    using namespace std::string_literals;
8
 
9
    std::string s1 = "abc\0\0def";
10
    std::string s2 = "abc\0\0def"s;
11
    std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";
12
    std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";
13
    std::puts (s2.c_str ());
14
    std::fwrite (s2.data (), 1, s2.size (), stdout);
15
    std::puts ("");
16
}
Ausgabe:
1
s1: 3 "abc"
2
s2: 8 "abc^@def"
3
abc
4
abc^@def
http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s

Der << Operator gibt den ganzen String aus, auch nach dem 0-Byte, weil 
das eine "richtige" C++-Ausgabe ist welche eben die Länge auswertet. 
puts geht nur bis zum 0-Byte, aber wenn man an fwrite die Länge übergibt 
wird alles ausgegeben. Die 0-Bytes werden entsprechend dem Terminal gar 
nicht oder irgendwie umschrieben ausgegeben (hier: ^@).

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Der Ctor von std::string interpretiert den C-String auch richtig. Also
>> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein
>> C-String der Länge 3 (per Konvention).
>
> Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick
> nutzen um die tatsächliche Länge zu erhalten... Ok, wenn man 0-Bytes
> übergibt muss man die Länge angeben:
>
1
std::string ("foo\0bar", 7);

Ja, denn der C-String endet per Definitionem am Sentinel. Deswegen macht 
der Typw.-ctor von std::string das auch korrekt.

> Wilhelm M. schrieb:
>> die BYtes vom
>> Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.
> Okay, wie hat man dann Bytes vom Netzwerk interpretiert bevor es
> std::byte gab?

Konnte man ja machen seit es scoped enums gibt (C++11).

> byte ist ja auch nur als enum vom typ unsigned char
> definiert.

Aber eben nich implizit konvertierbar in einen arithmetischen Typ 
(char).

> char darf definitiv 0 werden.

Ja klar.

> In Anbetracht der Tatsache dass die read/write -Funktionen von
> istream/ostream "char*" akzeptieren hätte ich jetzt gedacht, dass man
> char-Arrays, und damit auch std::string, sehr wohl zum Speichern von
> Netzwerkdaten nutzen kann.

Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C 
muss man das so machen schlechterdings.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> PS: Das User-Defined Literal "s" für std::string übernimmt 0-Bytes
> korrekt:

Beide sind korrekt (s.o.): d.h. sie interpretieren den Quelldatentyp 
richtig.

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C
> muss man das so machen schlechterdings.

Und wie macht man es in C++03? In C++17 arbeiten die read/write 
Funktionen immer noch mit "char*".
Und was willst du eigentlich sagen? Dass man in dem Code-Snippet kein 
std::string hätte verwenden dürfen, sondern std::byte? Wie wäre das in 
C++03 gegangen? Dass man mit strcmp hätte vergleichen müssen?

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C
>> muss man das so machen schlechterdings.
>
> Und wie macht man es in C++03?

Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.

struct byte {...};


> In C++17 arbeiten die read/write
> Funktionen immer noch mit "char*".

Nein, mit void*.

std::fwrite ist ein namespace-aware wrapper für POSIX-fwrite, mehr 
nicht.

> Und was willst du eigentlich sagen? Dass man in dem Code-Snippet kein
> std::string hätte verwenden dürfen, sondern std::byte?

Wenn man einen Protokollbuffer mit binären, nicht-numerischen Daten hat, 
dann wäre das ein std::array<std::byte, ...>, oder ein 
std::vector<std::byte>, aber kein std::string.

> Wie wäre das in
> C++03 gegangen?

Ja, aber da mache ich mir 15-Jahre später keine Gedanken mehr drüber.

> Dass man mit strcmp hätte vergleichen müssen?

Das vergleicht wieder nur C-Strings ... mit der (impliziten) Annahme, 
dass die übergebenen Zeiger auf eine Folge (mindestens eins) Zeichen des 
Typs const char zeigen, und dass diese Folge hoffentlich (keiner weiß 
es) mit '\0' abgeschlossen ist. Falls nicht ... ok wir kennen die Story. 
Sowas ist einfach nur Murks.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Der Ctor von std::string interpretiert den C-String auch richtig. Also
>> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein
>> C-String der Länge 3 (per Konvention).
>
> Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick
> nutzen um die tatsächliche Länge zu erhalten...

Ja, sowas hatte ich hier mal gepostet, damit man C-Strings (bspw. für 
AVR) automatisch in bestimmte Sections (flash) legen kann. Dazu hatte 
ich dann ein UDL-Op definiert: "abc"_pgm ist dann im Flash. Man kann 
auch das getrost N-mal im Code verwenden, es wird nur einmal ins flash 
gepackt.

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.

Also keine Erklärung. Top.

Wilhelm M. schrieb:
> Nein, mit void*.

http://en.cppreference.com/w/cpp/io/basic_istream/read
Also hier steht char_type und das ist char bei std::ifstream.

Wilhelm M. schrieb:
> aber kein std::string.

Wer sagt das? Und warum kann std::string dann problemlos damit umgehen? 
Das o.g. Problem existiert nur bei der Nutzung als C-String.

Wilhelm M. schrieb:
> Ja, sowas hatte ich hier mal gepostet
Daher kenn ich das nicht...

von Jobst Q. (joquis)


Lesenswert?

Dr. Sommer schrieb:
> BMP-Dateien enthalten z.B. Nullbytes. Wenn man die in einen std::string
> einliest möchte man die erhalten.

Was soll das für einen Sinn haben, eine Binärdatei in einen String 
einzulesen?


> Wenn man also eine Eingabe/Protokoll
> hat welches allgemein Binär-Daten überträgt, und es auch für Texte
> nutzt, werden 0-Bytes mit übernommen. Dies ist z.B. bei HTTP-Formularen
> der Fall; hier könnte ein Angreifer 0-Bytes mit senden. 0-Bytes in HTTP
> komplett auszuschließen würde aber das Hochladen von BMP-Dateien
> verhindern.

HTTP heißt Hypertext Transfer Protokoll. Es geht also um Texte. 0-Bytes 
haben in Texten aber nichts zu suchen.

Um Binärdateien zu übertragen, werden sie meines Wissens mit Base64 oder 
ähnlichem in Textdateien umgewandelt.

> Die 0-Bytes sind auch kein Problem, bis man ein solches Byte-Array an
> eine C/POSIX-Funktion übergibt.

Sie sind auch in purem C kein Problem, wenn man die mem-Funktionen 
verwendet. Der Fehler ist, die Byte-Arrays String zu nennen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.
>
> Also keine Erklärung. Top.

Lies genau: steht oben.

>
> Wilhelm M. schrieb:
>> Nein, mit void*.
>
> http://en.cppreference.com/w/cpp/io/basic_istream/read
> Also hier steht char_type und das ist char bei std::ifstream.

Du hast oben aber std::fwrite() benutzt.

>
> Wilhelm M. schrieb:
>> aber kein std::string.
>
> Wer sagt das? Und warum kann std::string dann problemlos damit umgehen?

Wenn Du die Protokollintegrität sicherstellen kannst und Du wirklich nur 
Zeichen überträgt, kannst Du es. Aber das wolltest Du ja nicht. Dein 
Beispiel zielt auf andere Szenarien ab. Und hier ist das Empfangene erst 
mal nur eine Folge von Bytes. Um es als eine Menge von Strings zu 
interpretieren, brauchst Du dann eben einen (robusten) Parser. Der 
filtert dann solche Sachen aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Leider sind die meisten Kernel in C geschrieben, und syscalls wie open
> nutzen 0-terminierte Strings, auch wenn man sie direkt aus C++ aus
> aufruft.

Ehrlich mal, POSIX hat genau zwei „verbotene“ Zeichen in Dateinamen,
das ist das Nullbyte und der Schrägstrich.

Vergleich' das mal mit anderen Betriebssystemen …

von Peter D. (peda)


Lesenswert?

Ich hatte das mal für das EA eDIPTFT43-A benötigt, daß Arrays \0 
beinhalten. Man kann sie als Strings definieren, aber natürlich nicht 
mit Stringfunktionen ausgeben.
Ich hab das mit einen Macro gelöst, was per sizeof die Länge ermittelt. 
Da an Strings immer ein 0-Byte angehängt wird, mußte ich noch 1 
abziehen:
1
#define TFT_FKT(x)      tft_wr( sizeof(x) - 1, x, 1 )
2
uint8_t tft_wr( uint8_t len, uint8_t *dat, bool flash ); // write to GLCD from SRAM or Flash
3
prog_uint8_t INIT[] =
4
                "\x1bTC\0"              // text cursor off
5
                "\x1b""DO\2"            // rotate 180°
6
                "\x1b""FD\x8\x1"        // display color
7
                "\x1b""FZ\x8\x1"        // text color
8
                "\x1b""DL"              // display clear
9
                "\x1b""YZ\x0"           // no delay
10
                "\x1b""YH\x64"          // light on
11
                ;
12
void tft_init( void )
13
{
14
  // ...
15
  TFT_FKT( INIT );
16
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Mmh ...
1
void init(uint8_t* s) {
2
    TFT_FKT(s);
3
}
4
5
int main() {
6
    init(INIT);
7
}

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Mmh ...
> void init(uint8_t* s) {
>     TFT_FKT(s);
> }
>
> int main() {
>     init(INIT);
> }

So geht's nicht, aber so, wie Peter geschrieben hat, schon.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Mmh ...
>> void init(uint8_t* s) {
>>     TFT_FKT(s);
>> }
>>
>> int main() {
>>     init(INIT);
>> }
>
> So geht's nicht, aber so, wie Peter geschrieben hat, schon.

Das ist mir schon klar: es ist DER Standardfehler. Deswegen sollte man 
den sizeof()-Operator nicht dort benutzen, wo ein Array-Bezeichner zu 
einem Zeiger zerfällt.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Deswegen sollte man den sizeof()-Operator nicht dort benutzen, wo ein
> Array-Bezeichner zu einem Zeiger zerfällt.

Ich glaube, dessen ist sich Peter durchaus bewusst.

Deswegen übergibt er INIT ja auch nicht per Funktionsargument an
tft_init, sondern greift direkt darauf zu.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Deswegen sollte man den sizeof()-Operator nicht dort benutzen, wo ein
>> Array-Bezeichner zu einem Zeiger zerfällt.
>
> Ich glaube, dessen ist sich Peter durchaus bewusst.

Ihm mag das ja klar sein. Trotzdem fällt damit dieses Macro in die 
Kategorie "Leicht falsch zu benutzen".

> Deswegen übergibt er INIT ja auch nicht per Funktionsargument an
> tft_init, sondern greift direkt darauf zu.

Du siehst aber, wie schnell man den Fehler machen kann. Vor allem etwas 
"unbedarfte" Anwender, die sich über dieses function-like Macro keine 
gedanken machen. So etwas sollte heute nicht mehr möglich sein!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu
> benutzen".

Genau darum schreibt man ja Makros auch GROSS.  Damit ist klar, dass
es ein Makro ist und eben keine Funktion, und dass man sich um dessen
Randbedingungen Gedanken machen muss, wenn man ihn benutzt.

Klar könnte man das in C++ alles viel schöner und eleganter schreiben.
Das hilft dir aber gar nichts, wenn du sowas in einem Projekt brauchst,
das über x Jahre mehrere hunderttausend Codezeilen akkumuliert hat, und
für das dir kein Kunde den Aufwand bezahlen würde, es ohne grundlegende
Erweiterung der Funktionalität nur der Eleganz und Schönheit wegen von
C in eine andere Sprache umzuschreiben.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu
> benutzen".

Fällt nicht das komplette C/C++ in diese Kategorie? ;-)

SCNR

von Wilhelm M. (wimalopaan)


Lesenswert?

Jörg W. schrieb:
> Wilhelm M. schrieb:
>> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu
>> benutzen".
>
> Genau darum schreibt man ja Makros auch GROSS.

Was aber für den Präprozessor / Compiler unerheblich ist.

> Damit ist klar, dass
> es ein Makro ist und eben keine Funktion, und dass man sich um dessen
> Randbedingungen Gedanken machen muss, wenn man ihn benutzt.

Wenn sich alle Programmierer immer alle Gedanken machen würde, gäbe es 
keine Bugs. Dem scheint aber nicht so zu sein ;-) Es ist besser, wenn 
der Code bei falscher Verwendung der Schnittstelle nicht compiliert.

> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.

Du kannst meine Gedanken lesen ;-)

Es wäre schöner, eleganter, sicherer und vermutlich effizienter gewesen.

> Das hilft dir aber gar nichts, wenn du sowas in einem Projekt brauchst,
> das über x Jahre mehrere hunderttausend Codezeilen akkumuliert hat, und
> für das dir kein Kunde den Aufwand bezahlen würde, es ohne grundlegende
> Erweiterung der Funktionalität nur der Eleganz und Schönheit wegen von
> C in eine andere Sprache umzuschreiben.

Das wollte ich damit auch gar nicht bezwecken. Ich kenne so etwas zur 
Genüge.

Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich 
an der Situation leider nichts ändern. Man muss zumindest deutlich 
hervorgehoben werden. Was ich damit getan habe.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu
>> benutzen".
>
> Fällt nicht das komplette C/C++ in diese Kategorie? ;-)

Das will ich gar nicht in Gänze bestreiten.

Allerdings sehe ich einen wesentlichen Unterschied:

In C kann man es leider nicht wirklich besser machen, in C++ hat man die 
Möglichkeiten. Und gute Library-API-Designer nutzen diese Möglichkeiten.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Jörg W. schrieb:
> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.

Das Beispiel braucht kein C++ um einigermassen wasserdicht zu werden.

Statt das sizeof() ins Makro zu schreiben eine entsprechende Konstante 
definiert:
1
#define TFT_FKT(x)      tft_wr(INIT_SIZE - 1, x, 1 )
2
static const size_t INIT_SIZE = sizeof(INIT);

die und das Array hinter "static" versteckt, das Ganze in eine separate 
Übersetzungseinheit, nur noch die Funktion nach aussen sichtbar und 
schon ist das wesentlich ungefährlicher.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:

> Das Beispiel braucht kein C++ um einigermassen wasserdicht zu werden.

… allerdings massiv auf Kosten der Benutzerfreundlichkeit.

von Wilhelm M. (wimalopaan)


Lesenswert?

Markus F. schrieb:
> Jörg W. schrieb:
>> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.
>
> Das Beispiel braucht kein C++ um einigermassen wasserdicht zu werden.
>
> Statt das sizeof() ins Makro zu schreiben eine entsprechende Konstante
> definiert:
>
>
1
> #define TFT_FKT(x)      tft_wr(INIT_SIZE - 1, x, 1 )
2
> static const size_t INIT_SIZE = sizeof(INIT);
3
>
>
> die und das Array hinter "static" versteckt, das Ganze in eine separate
> Übersetzungseinheit, nur noch die Funktion nach aussen sichtbar und
> schon ist das wesentlich ungefährlicher.

Ok, wenn das Macro weg ist, habe ich sicher kein Problem mehr damit ;-)

Wenn die Signatur von tft_wr() so bleibt, habe ich aber nichts gewonnen. 
Das Macro versuchte gerade, die Fehlermöglichkeiten der Schnittstelle zu 
eliminieren, was aber nicht funktioniert. Jetzt haben wir es wieder mit 
den zwei "zusammenhanglosen" Parametern zu tun ... oh, es sind sogar 
drei Parameter, die eine semantische Einheit bilden.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Peter D. schrieb:
> prog_uint8_t INIT[] =
>                 "\x1bTC\0"              // text cursor off
>                 "\x1b""DO\2"            // rotate 180°
>                 "\x1b""FD\x8\x1"        // display color
>                 "\x1b""FZ\x8\x1"        // text color
>                 "\x1b""DL"              // display clear
>                 "\x1b""YZ\x0"           // no delay
>                 "\x1b""YH\x64"          // light on
>                 ;

wo ist da eigentlich der Vorteil zu plain C?
1
#define NEW_CMD (0x1b)
2
prog_uint8_t INIT[] = {
3
    NEW_CMD, 'T','C', 0,    // text cursor off
4
    NEW_CMD, 'D','O', 2,    // rotate 180°
5
    NEW_CMD, 'F','D', 8, 1, // display color
6
    NEW_CMD, 'F','Z', 8, 1, // text color
7
    NEW_CMD, 'D','L',       // display clear
8
    NEW_CMD, 'Y','Z', 0,    // no delay
9
    NEW_CMD, 'Y','H', 100   // light on
10
    }
11
12
/* Bzw, wenn die vielen '' stören: */
13
#define CMD(x,y) 0x1b, 'x', 'y'
14
prog_uint8_t INIT[] = {
15
    CMD(T,C), 0,    // text cursor off
16
    CMD(D,O), 2,    // rotate 180°
17
    CMD(F,D), 8, 1, // display color
18
    CMD(F,Z), 8, 1, // text color
19
    CMD(D,L),       // display clear
20
    CMD(Y,Z), 0,    // no delay
21
    CMD(Y,H), 100   // light on
22
    }

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich
> an der Situation leider nichts ändern.

Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel 
eleganter erschlagen kann. Nur muß man das erst finden und auch 
verstehen.

Ich wollte auch verdeutlichen, daß man Strings und Arrays nicht einfach 
in einen Topf werfen kann. Für Arrays funktioniert strlen nicht mehr und 
man muß sich eine andere Methode ausdenken, um die Länge zu ermitteln.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:

> Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel
> eleganter erschlagen kann. Nur muß man das erst finden und auch
> verstehen.

Das "Geschütz" nennt sich dort einfach "Objekt" … man definiert sich
eine Klasse, die intern außer dem Bytehaufen auch noch die Länge als
Eigenschaft hat.  Durch einen passenden Konstruktor kann man beim
Erzeugen eines Objekts (also einer Instanz dieser Klasse) dann einen
ganz normalen String als Initialisierer angeben.

Sehr wahrscheinlich gibt es sogar so eine Klasse schon irgendwie
irgendwo, andererseits ist das so einfach, dass man es als C++-Einstieg
durchaus auch als Fingerübung benutzen kann, das mal selbst zu zimmern.

von Dr. Sommer (Gast)


Lesenswert?

So sollte es gehen:
1
prog_uint8_t INIT[] =
2
                "\x1bTC\0"              // text cursor off
3
                "\x1b""DO\2"            // rotate 180°
4
                "\x1b""FD\x8\x1"        // display color
5
                "\x1b""FZ\x8\x1"        // text color
6
                "\x1b""DL"              // display clear
7
                "\x1b""YZ\x0"           // no delay
8
                "\x1b""YH\x64"          // light on
9
10
void tft_wr (prog_uint8_t* arr, std::size_t length) {
11
  // Normales Senden
12
}
13
14
template <typename T, std::size_t N>
15
inline void tft_wr (T (&arr) [N]) {
16
  tft_wr (arr, N);
17
}
18
19
int main () {
20
  tft_wr (INIT);
21
}

Mit etwas Bastelei ginge auch sowas:
1
constexpr auto INIT = combine (
2
  textCursorOff (),
3
  rotate (180),
4
  displaColor ()
5
  ...
6
);
7
...
Wobei textCursorOff () usw die einzelnen Befehle erzeugen, und combine 
daraus ein Array macht. Kann ich aber gerade nicht vollständig 
ausführen. Wäre so dann auch hübsch:
1
tft_wr (rotate (180));

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Wilhelm M. schrieb:
>> Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich
>> an der Situation leider nichts ändern.
>
> Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel
> eleganter erschlagen kann. Nur muß man das erst finden und auch
> verstehen.

So schlimm ist das ja eigentlich gar nicht. Allerdings ist der 
Ausgangspunkt ,eine Kommandosequenz sei ein String, nicht gut.

Ein Kommando für dieses Display sind zwei Codes (Ascii-Zeichen) und dann 
eine Payload. Die Kommandos können im Binär- oder Ascii-Modus gesendet 
werden. Im Binär-Modus haben wir ein anderes Startbyte als im 
Ascii-Modus, wo auch noch Trennzeichen gesendet werden sowie alles 
dezimal codiert wird.

Daraus kann man erkennen, dass das Startbyte nicht zum Command gehört 
und auch die Trennzeichen etc. erst durch die Realisierung des 
Übertragungsmodus bestimmt werden.

Man könnte ein Kommando also einfach als Folge von Bytes darstellen:
1
    std::array<std::byte, Size> command;

Allerdings ist das einzig Variable an einem festen Kommando die Payload, 
deswegen kann man die zwei Codes des Kommandos auch gleich in den Typ 
einbeziehen (und noch Bytes sparen):
1
template<char F, char S, auto Size>
2
struct Command {
3
    template<typename... VV>
4
    constexpr Command(VV... vv) : data{vv...} {}
5
    std::array<std::byte, Size> data;  
6
};

Damit kann man ein Kommando instanziieren:
1
    auto c1 = Command<'T', 'C', 2>{std::byte{8}, std::byte{1}};

Ob man das Kommando als std::array oder eigenes Template realisiert, man 
hat es auf jedenfall mit unterschiedlichen Typen der Kommandos zu tun. 
Deswegen kann man für eine Kommandosequenz keine homogenen Container 
benutzen wie std::array<typ-der-commandos, anzahl>, sondern man braucht 
einen heterogenen Container, etwa std::tuple:
1
    auto c1 = Command<'T', 'C', 2>{std::byte{8}, std::byte{1}};
2
    auto c2 = Command<'G', 'CD', 1>{std::byte{1}};
3
    
4
    auto sequence = std::tuple(c1, c2);

Dabei ist natürlich lästig, die Länge der Payload explizit angeben zu 
müssen und auch die explizite Typwandlung nach std::byte ist zwar gut, 
aber sehr verbose.

Das geht dann mit einer Factory-Funktion einfacher:
1
template<char F, char S, typename... VV>
2
constexpr auto command(VV... vv) {
3
    return Command<F, S, sizeof...(VV)>(vv...);
4
}
Die Funktionen leitet die Länge ab und erzeugt die passenden 
Parameterierung.

Also:
1
    auto c3 = command<'T', 'C'>(std::byte{8}, std::byte{1});

(Ein user-defined deduction-guide geht hier nicht wegen der expl. 
Instanziierung durch die Kommando-Codes).

Jetzt ist noch das std::byte etwas lästig, dafür bieten sich 
UDL-Operatoren an:
1
constexpr std::byte operator"" _B(char c) {
2
    return std::byte(c);
3
}

Nun kann man schreiben:
1
    constexpr auto init_sequence = std::make_tuple(
2
                command<'T', 'C'>(0_B, 1_B),
3
                command<'D', 'O'>(2_B)
4
                );

Um die Sequenz ausgeben zu können:
1
template<typename Commands>
2
void tft_write(const Commands& commands) {
3
    std::apply([](auto... c){
4
        // Assertion, das c den richtigen Typ hat, oder familiar-template syntax für diese lambda-expr (c++20)
5
        // Ausgabe auf Ascii- oder Binär-Interface
6
    }, commands);
7
}

Dies geht dann mit jedem Container, der die Anforderungen von 
std::apply<>() erfüllt.
Die Art des Inferfaces entscheidet dann über Start-Byte, Trennzeichen, 
Prüfsumme, etc...

Wenn man sich noch etwas mehr Mühe gibt, kann man auch statisch prüfen, 
ob die Kombination der beiden Ascii-Codes Sinn macht und ob die Payload 
dazu passt. Wie gesagt: statisch. Bei einem Fehler würde das Programm 
nicht compilieren! Man muss also zur Laufzeit dahingehend ggf. nichts 
debuggen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dr. Sommer schrieb:
> tft_wr (arr, N);

Das sollte
1
  tft_wr (arr, N-1);

heißen, damit das String-Ende-'\0' nicht mit ausgegeben wird.

Im Prinzip gefällt mir deine Lösung gut, aber hundertprozentig
anfängertauglich ist auch sie nicht unbedingt:

Wilhelm kritisierte an Peters Lösung, dass damit folgendes nicht möglich
ist:

1
void init(uint8_t* s) {
2
    TFT_FKT(s);
3
}
4
5
int main() {
6
    init(INIT);
7
}

Möchte man das mit deiner Methode realisieren, muss auch init eine
Template-Funktion sein:

1
template <typename T, std::size_t N>
2
inline void init(T (&arr) [N]) {
3
  tft_wr(arr);
4
  // weiterer Initialisierungcode
5
  // ...
6
}

Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings
genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf
den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei
sehr umfangreichem init-Code nicht erwünscht ist.

Wenn man sich des Problems bewusst ist, kann man es leicht umgehen. Wenn
der Programmierer aber dazu in der Lage ist, ist er kein blutiger
Anfänger mehr, so dass für ihn auch das von Wilhelm angeführte Problem
mit dem zum Zeiger zerfallenden Array keines darstellt.

Deswegen stellt sich für mich generell die Frage, wieviel Aufwand man in
zusätzlichem Quellcode man stecken sollte, um damit Programmierfehler zu
vermeiden, die nur mit sehr geringer Wahrscheinlichkeit passieren (in
dem Moment, wo man beginnt, nach einer Alternativlösung zu suchen, hat
man die Gefahr ja schon erkannt und wird deswegen nicht mehr in die
Falle tappen).

Dabei denke ich jetzt weniger an deine Lösung (die ja sehr kompakt und
relativ schnell hingeschrieben ist), sondern an Wilhelms Vorschläge, die
sich oft über zig Codezeilen erstrecken.

@Wilhelm:

Betrachte das, was ich hier schreibe, bitte nicht als generelle Kritik
an deiner Art und Weise zu programmieren. Ich kann aus deinen Beispielen
viel lernen, und ich werde viele deiner Vorschläge künftig auch in
meinem eigenen Code umsetzen, nur nicht unbedingt in so einfachen
Kontexten, wo ich befürchte, dass der Aufwand schnell mal den Nutzen
übersteigt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings
> genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf
> den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei
> sehr umfangreichem init-Code nicht erwünscht ist.

Das ist zwar grundsätzlich richtig, allerdings ist der Effekt in der 
Praxis vernachlässigbar bzw. geht im Rauschen unter. Der Grund dafür 
ist, dass das Compilerfrontend den template-code i.A: besser optimieren 
kann (s.u.).


> @Wilhelm:
>
> Betrachte das, was ich hier schreibe, bitte nicht als generelle Kritik
> an deiner Art und Weise zu programmieren. Ich kann aus deinen Beispielen
> viel lernen, und ich werde viele deiner Vorschläge künftig auch in
> meinem eigenen Code umsetzen, nur nicht unbedingt in so einfachen
> Kontexten, wo ich befürchte, dass der Aufwand schnell mal den Nutzen
> übersteigt.

Das kann jeder gerne so halten, wie er möchte. Ich kann dazu nur sagen, 
dass wir seit Jahren genau diese Strategie verfolgen und damit wirklich 
sehr erfolgreich sind. Der Code, den ich hier ab und zu mal poste bzw. 
die Kommentare, die ich dazu abgebe, sind dann immer aus Sicht des 
Library-Guys, also des Generalisten. Das kann man auch oben sehen, denn 
es ist nun ganz leicht, einen Protokolladapter für das Ascii-Protokoll 
oder einen für das Binärprotokoll des Displays dazwischen zu schieben, 
was natürlich bei der alles-ist-ein-String-Variante nicht geht, die die 
Grenzen zwischen den Kommandos und ihren Bestandteilen sind ja nicht 
(statisch) sichtbar.

Grundsätzlich haben wir folgende Ziele:

* Header-Only Template Code
* Möglichst viele Fehler zur Compilezeit
* Permanentes Code-Refreshment auf Bibliotheksebene (full C++ feature 
set)

Zwar ist AVR nicht unsere Zielplattform sondern SAM/ARM, aber auch dort 
bleibt der allseits postulierte Code-Bloat aus.

Das wesentliche ist dem Compiler so viel statische Information wie 
möglich mitzugeben bzw. die Datentypen optimal zu wählen: Werte sind 
bedeutungslos, Datentypen sind alles. Die Vorteile dieser Strategie 
scheinen evtl. Nachteile (etwa durch Mehrfachinstanziierungen) 
auszugleichen, das zeigen jedenfalls exemplarische Untersuchungen, die 
wir mal gemacht haben.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
>> Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings
>> genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf
>> den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei
>> sehr umfangreichem init-Code nicht erwünscht ist.
>
> Das ist zwar grundsätzlich richtig, allerdings ist der Effekt in der
> Praxis vernachlässigbar bzw. geht im Rauschen unter. Der Grund dafür
> ist, dass das Compilerfrontend den template-code i.A: besser optimieren
> kann (s.u.).

Das mag manchmal zutreffen, im gerade diskutieren Fall wird aber an den
Templates überhaupt nichts optimiert.

Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die
nacheinander alle durch einen Aufruf von init an das Display geschickt
werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich
in init ein paar Rechenoperationen angefügt.


test.cpp:
1
#include <stddef.h>
2
#include <stdint.h>
3
4
uint8_t INIT1[] = "\x1b""A";
5
uint8_t INIT2[] = "\x1b""BB";
6
uint8_t INIT3[] = "\x1b""CCC";
7
uint8_t INIT4[] = "\x1b""DDDD";
8
9
void tft_wr(uint8_t* arr, size_t length);
10
11
template <typename T, size_t N>
12
inline void tft_wr(T (&arr) [N]) {
13
  tft_wr(arr, N);
14
}
15
16
volatile uint32_t a, b, c, d;
17
18
template <typename T, size_t N>
19
inline void init(T (&arr) [N]) {
20
  tft_wr(arr);
21
22
  // relativ viel zusätzlicher Code
23
  a = b + c; d = a + b; c = d + a; b = c + d;
24
  a = b + c; d = a + b; c = d + a; b = c + d;
25
}
26
27
int main() {
28
  init(INIT1);
29
  init(INIT2);
30
  init(INIT3);
31
  init(INIT4);
32
}

Diesen Code habe ich für einen AVR kompiliert und mir die Größe der
erzeugten Objektdatei ausgeben lassen:

1
avr-gcc -mmcu=atmega8 -std=c++17 -Os -c test.cpp
2
avr-size test.o

Die Größe der text-Section ist mit einem einzelnen init-Aufruf

  468 Bytes,

mit allen 4 Aufrufen

  1854 Bytes,

also fast das Vierfache. Der Compiler erzeugt tatsächlich 4 Instanzen
der Template-Funktion, deren Assembler-Code jeweils 132 Instruktionen
lang ist und sich nur in einer einzigen Instruktion von den anderen
Instanzen unterscheidet.

Diesen schon sehr deutlichen Zuwachs der Codegröße kann man in diesem
Beispiel vermeiden, indem man den von den Template-Parametern
unabhängigen Teil der init-Funktion in eine separate Funktion auslagert.
Dazu muss man sich aber erst einmal des Problems bewusst werden und darf
nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.

von Carl D. (jcw2)


Lesenswert?

Yalu X. schrieb:
> Die Größe der text-Section ist mit einem einzelnen init-Aufruf
>
>   468 Bytes,
>
> mit allen 4 Aufrufen
>
>   1854 Bytes,
>
> also fast das Vierfache. Der Compiler erzeugt tatsächlich 4 Instanzen
> der Template-Funktion, deren Assembler-Code jeweils 132 Instruktionen
> lang ist und sich nur in einer einzigen Instruktion von den anderen
> Instanzen unterscheidet.
Auch wenn init static, also "wirklich nur hier gebraucht", ist bzw. LTO 
benutzt wird?

Gerade getestet:
  - gcc8.1
  - "static" vor allen Funktionen (außer Main) oder LTO,
  - O3
-> 586 Bytes .text

> Diesen schon sehr deutlichen Zuwachs der Codegröße kann man in diesem
> Beispiel vermeiden, indem man den von den Template-Parametern
> unabhängigen Teil der init-Funktion in eine separate Funktion auslagert.
> Dazu muss man sich aber erst einmal des Problems bewusst werden und darf
> nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.
Doch, darf man!
Man muß ihm nur die nötige Info mitgeben, z.B. daß Funktionen niemals 
von außerhalb gerufen werden.
Oder eben über den"Trick" LTO, dann bekommt er das selber raus.

PS: einmal init -> 576 Bytes, ergo: kein Bloat!

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Carl D. schrieb:
> Auch wenn init static, also "wirklich nur hier gebraucht", ist bzw. LTO
> benutzt wird?

Bei mir ändert sich die Codegröße dadurch nur marginal.

Carl D. schrieb:
> - "static" vor allen Funktionen (außer Main) oder LTO,

Was machst du mit

1
void tft_wr(uint8_t* arr, size_t length);

?

Ich bin davon ausgegangen, dass das eine externe Bibliotheksfunktion
ist. Wenn du sie ebenfalls static machen möchtest, musst du natürlich
dafür sorgen, dass sie irgendetwas mit dem Argument length anstellt,
bspw. so:

1
static void tft_wr(uint8_t* arr, size_t length) {
2
  volatile size_t dummy = length;
3
}

Sonst unterscheiden sich die 4 Template-Instanzen nicht voneinander und
können durch den Compiler zu einer einzigen zusammengefasst werden.

: Bearbeitet durch Moderator
von Heiko L. (zer0)


Lesenswert?

Carl D. schrieb:
>> Dazu muss man sich aber erst einmal des Problems bewusst werden und darf
>> nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.
> Doch, darf man!
> Man muß ihm nur die nötige Info mitgeben, z.B. daß Funktionen niemals
> von außerhalb gerufen werden.

Mal anders argumentiert: Die Größe des Arrays ist in dem einen Fall ein 
Datum, mit dem ein Algorithmus arbeitet, in dem anderen Fall ein 
Parameter des Algorithmus selbst.
 und
kann man sicher so definieren, dass sie das selbe Ergebnis liefern. Aber 
in dem einen Fall ist die 35 ein Argument einer Funktion die somit 
allgemeiner anzuwenden ist.
Das wird bei den Beispielen hier schon dann deutlich, wenn man mal 
versucht eine unbestimmte Menge von Kommandos aus einer Datei 
einzulesen...

Beitrag #5452274 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die
> nacheinander alle durch einen Aufruf von init an das Display geschickt
> werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich
> in init ein paar Rechenoperationen angefügt.

Du hast ein Beispiel konstruiert(!), was natürlich eine starke 
Vermehrung des Maschinencodes bewirkt. Dies ist allerdings durch die 
volatile Qualifizierung im template entstanden. Dies entspricht 
allerdings nicht der Praxis.

In der Praxis haben wir SFRs, die notwendigerweise volatile qualifiziert 
sind, oder (ganz wenige) Datenstrukturen, die nebenläufig verwendet 
werden, und deswegen volatile sind.

Jetzt komme ich mit einem etwas praxisrelevanteren Beispiel: wir wollen 
die Daten der Arrays durch ein Protokoll laufen lassen und dann auf 
irgendeiner Schnittstelle ausgeben. Die Schnittstelle ist hier einfach 
mal als ein SFR dargestellt. Natürlich soll das ganze ein bisschen 
modular sein: unterschiedliche Protokolle mit unterschiedlichen 
Schnittstellen kombinierbar.

Variante A in C:
main.c:
1
#include <stdint.h>
2
#include <stddef.h>
3
4
typedef void (*dev_t)(uint8_t);
5
6
void protocol_A(const uint8_t* data, uint8_t length, dev_t dev);
7
8
void spi1_put(uint8_t data);
9
10
uint8_t a1[2];
11
uint8_t a2[4];
12
13
int main(){
14
    protocol_A(a1, sizeof(a1), spi1_put);
15
    protocol_A(a2, sizeof(a2), spi1_put);
16
}
und lib.c
1
#include <stdint.h>
2
#include <stddef.h>
3
4
typedef void (*dev_t)(uint8_t);
5
6
volatile uint8_t sfr1;
7
void spi1_put(uint8_t data) {
8
    sfr1 = data;
9
}
10
11
void protocol_A(const uint8_t* data, uint8_t length, dev_t dev) {
12
    for(uint8_t i = 0; i < length; ++i) {
13
        dev(data[i]);
14
    }
15
}

Variante B in C++:
lib.h
1
#include <cstdint>
2
#include <cstddef>
3
#include <array>
4
5
template<auto N>
6
struct Spi final {
7
    static void put(std::byte data) {
8
        sfr = data;
9
    }
10
    inline static volatile std::byte sfr;
11
};
12
13
struct A;
14
15
template<typename Kind, typename Dev>
16
struct Protocol final {
17
    template<auto L>
18
    static constexpr void put(const std::array<std::byte, L>& data) {
19
        for(const auto& v : data) {
20
            Dev::put(v);
21
        }
22
    }
23
};
und main.cc:
1
#include "lib.h"
2
3
using spi  = Spi<0>;
4
using p1   = Protocol<A, spi>;
5
6
std::array<std::byte, 2> a1;
7
std::array<std::byte, 4> a2;
8
9
int main(){
10
    p1::put(a1);
11
    p1::put(a2);
12
}

Da bekomme ich für das Target atmega328:

C:   238 Bytes text, 7 Bytes bss
C++: 188 Bytes text, 7 Bytes bss

Wenn ich für die C-Variante LTO einschalte:
C:   198 Bytes text, 7 Bytes bss

Soweit zu Beispielen (frei nach Pipi Langstrumpf!).

Hinzu kommt m.E. der besser strukturierte und sicherere Code. Wenn man 
das Beispiel erweitert auf:
1
using spi1  = Spi<0>;
2
using spi2  = Spi<1>;
3
using p1   = Protocol<A, spi1>;
4
using p2   = Protocol<A, spi2>;
5
6
std::array<std::byte, 2> a1;
7
std::array<std::byte, 4> a2;
8
std::array<std::byte, 8> a3;
9
std::array<std::byte, 16> a4;
10
11
int main(){
12
    p1::put(a1);
13
    p1::put(a2);
14
    p2::put(a3);
15
    p2::put(a4);
16
}

bzw.:
1
void spi1_put(uint8_t data);
2
void spi2_put(uint8_t data);
3
4
uint8_t a1[2];
5
uint8_t a2[4];
6
uint8_t a3[8];
7
uint8_t a4[16];
8
9
int main(){
10
    protocol_A(a1, sizeof(a1), spi1_put);
11
    protocol_A(a2, sizeof(a2), spi1_put);
12
    protocol_A(a3, sizeof(a3), spi2_put);
13
    protocol_A(a4, sizeof(a4), spi2_put);
14
}

so haben wir (mit LTO für C):

C:   272 Bytes text, 32 Bytes bss
C++: 224 Bytes text, 32 Bytes bss

Also hier sehen wir nichts von Code-Bloat, im Gegenteil.

von Markus F. (mfro)


Lesenswert?

Schreib' mal in der C-Variante noch ein static vor das volatile.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>
>> Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die
>> nacheinander alle durch einen Aufruf von init an das Display geschickt
>> werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich
>> in init ein paar Rechenoperationen angefügt.
>
> Du hast ein Beispiel konstruiert(!), was natürlich eine starke
> Vermehrung des Maschinencodes bewirkt. Dies ist allerdings durch die
> volatile Qualifizierung im template entstanden. Dies entspricht
> allerdings nicht der Praxis.

Konstruiert ist nur dieser Teil als Beispiel für einen etwas größeren
Codeabschnitt:

1
volatile uint32_t a, b, c, d;
2
3
  ...
4
  // relativ viel zusätzlicher Code
5
  a = b + c; d = a + b; c = d + a; b = c + d;
6
  a = b + c; d = a + b; c = d + a; b = c + d;

Ersetze ihn durch irgendwelchen sinnvollen, ähnlich großen Code, der
frei von volatiles ist, und du wirst feststellen, dass er immer noch für
jeden init-Aufruf dupliziert wird.

Wie ich oben geschrieben habe, kann das Problem dadurch behoben werden,
dass der gemeinsame, von den Template-Parameter unabhängige Code in eine
separate Funktion ausgelagert werden.

Fakt ist aber dass diese Optimierung durch den Programmierer geschehen
muss, der Compiler ist dazu (noch) nicht in der Lage.

> Jetzt komme ich mit einem etwas praxisrelevanteren Beispiel: wir wollen
> die Daten der Arrays durch ein Protokoll laufen lassen und dann auf
> irgendeiner Schnittstelle ausgeben.

Ich schrieb ja nicht, dass der Code-Bloat immer auftritt. In deinem
Beispiel tritt das Problem deswegen nicht in Erscheinung, weil die
put-Funktionen sehr klein sind. Sobald diese Funktionen etwas mehr tun
als nur ein paar Bytes zu kopieren, wirst du auch hier die
Codeduplizierung bemerken.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:

> Ersetze ihn durch irgendwelchen sinnvollen, ähnlich großen Code, der
> frei von volatiles ist, und du wirst feststellen, dass er immer noch für
> jeden init-Aufruf dupliziert wird.

Das stimmt auf der einen Seite, auf der anderen Seite entstehen durch 
den Template-Code größere Optimierungspotentiale (sowohl durch den 
Compiler wie auch im Algorithmus selbst) wie oben schon gesagt.

Vielleicht wird es deutlich, warum in Summe kein Code-Bloat auftritt, 
wenn wir unser Protokoll für längere Folgen erweitern und fügen eine 
Summe hinzu:
1
void protocol_A(const uint8_t* data, uint16_t length, dev_t dev) {
2
    uint32_t sum = 0;
3
    for(uint16_t i = 0; i < length; ++i) {
4
        dev(data[i]);
5
        sum += data[i];
6
    }
7
    dev(sum);
8
    dev(sum >> 8);
9
    if (length >= 256) {
10
        dev(sum >> 16);
11
        dev(sum >> 24);
12
    }
13
}

bzw:
1
template<typename Kind, typename Dev>
2
struct Protocol final {
3
    template<auto L>
4
    static constexpr void put(const std::array<std::byte, L>& data) {
5
        using sum_type = std::conditional_t<(L < 256), uint16_t, uint32_t>;
6
        sum_type sum = 0;
7
        for(const auto& v : data) {
8
            sum += std::to_integer(v);
9
            Dev::put(v);
10
        }
11
        std::byte lower_sum = std::byte(sum);
12
        std::byte upper_sum = std::byte(sum>> 8);
13
        Dev::put(lower_sum);
14
        Dev::put(upper_sum);
15
        if constexpr(L >= 256) {
16
            std::byte lower2_sum = std::byte(sum >> 16);
17
            std::byte upper2_sum = std::byte(sum >> 24);
18
            Dev::put(lower2_sum);
19
            Dev::put(upper2_sum);
20
        }
21
    }
22
};

Der Unterschied wird weiter größer zu Gunsten C++.

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.