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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
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. (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) (Moderator) 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) (Moderator) 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. (achs)


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. (achs)


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. (achs)


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. (achs)


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. (achs)


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. (achs)


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.