Forum: Mikrocontroller und Digitale Elektronik C modulo operation


von timi16 (Gast)


Lesenswert?

Hallo,
Wieso liefern folgende schnippsel unterschiedliche ergebnisse?
Erstes schnippsel gibt nur 0 für jedes j aus. ich hätte gedacht das 
beide Schnippsel für j werte zwischen 0..4 liefern.
1
    for(int i=0; i<100; i++) {
2
       j = ((j++) % (5));
3
        printf("%d\n",j);
4
    }
1
    for(int i=0; i<100; i++) {
2
       j = ((j+1) % (5));
3
        printf("%d\n",j);
4
    }

von Thomas R. (r3tr0)


Lesenswert?

timi16 schrieb:
> Hallo,
> Wieso liefern folgende schnippsel unterschiedliche ergebnisse?
> Erstes schnippsel gibt nur 0 für jedes j aus. ich hätte gedacht das
> beide Schnippsel für j werte zwischen 0..4 liefern.
>     for(int i=0; i<100; i++) {
>        j = ((j++) % (5));
>         printf("%d\n",j);
>     }
>     for(int i=0; i<100; i++) {
>        j = ((j+1) % (5));
>         printf("%d\n",j);
>     }


probiere mal ++j aus und j+1
j = 0;
i = 0;
i = j++; //hier ist i immer noch 0

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

timi16 schrieb:
> Wieso liefern folgende schnippsel unterschiedliche ergebnisse?

j=j++ ist ein klassischer Fall für undefined behavior. Da gibt es dann 
tatsächlich doch manchmal überraschende Ergebnisse.

Oliver

von Achim H. (anymouse)


Lesenswert?

Der Fehler steckt vermutlich in "j = ((j++) % (5));" -- kommt da keine 
Warnung?
Wahrscheinlich wird erst der rechte Ausdruck ausgewertet, dann j 
inkremiert, und dann der vorherige Ausdruckswert ebenfalls j zugewiesen 
und damit der inkremierte Wert überschrieben.

von Peter D. (peda)


Lesenswert?

Der erste Schnipsel sollte ne Warnung werfen, weil 2 Zuweisungen auf 
eine Variable.
Typisch wird der Compiler die linke Zuweisung zuletzt ausführen, muß er 
aber nicht.
1
main.c:12:10: warning: operation on 'j' may be undefined [-Wsequence-point]
2
        j = ((j++) % (5));
3
          ^

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


Lesenswert?

timi16 schrieb:
> j = ((j++) % (5));
Spiel mal Compiler und rechne das durch.
Beginnen wir mit der rechten Seite mit dem Wert j=0:

(j++) % 5

Aha, von links nach rechts kommen wir auf ein j, das mit dem 
Postincrement dazu angewiesen wird, dass erst nach der Operation 
incrementiert werden soll.

Also steht da j%5 und damit 0%5 und damit ist das Ergebnis der 
Berechnung 0 (merke 0).

Weil die Berechnbung nun fertig ist, können wir j incrementieren: j=1.

Aaaaaber: jetzt kommt das Gleichheitszeichen und per diesem wird das 
Ergebnis der Berechnung (gemerkt: 0)an j zugewiesen. Nach Bearbeiten der 
Zeile ist somit j=0.

> j = ((j++) % (5));
BTW: Fehlen da nicht noch ein paar Klammern?

von timi16 (Gast)


Lesenswert?

Ich bin voll überrascht. Ich kenne C seit 20 jahren und ich hätte 
gedacht das beide Schleifenschnippsel sich gleich verhalten.

Hier mal das ganze Program:
1
#include <stdio.h>
2
3
int main()
4
{
5
    int j=0;
6
    
7
    for(int i=0; i<100; i++) {
8
       j = ((j++) % (5));
9
        printf("%d\n",j);
10
    }
11
    
12
    for(int i=0; i<100; i++) {
13
       j = ((j+1) % (5));
14
        printf("%d\n",j);
15
    }
16
    
17
    return 0;
18
}

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


Lesenswert?

Was passiert wohl damit:
1
    for(int i=0; i<100; i++) {
2
        j = (j=j+1) % 5;
3
        printf("%d\n",j);
4
    }

von timi16 (Gast)


Lesenswert?

>> BTW: Fehlen da nicht noch ein paar Klammern?
Ich habe den inkrementierteil extra eingeklammert. Ich dachte das 
klammern bewirkt IMMER, dass ermal der Ausdruck in der klammer 
ausgeführt wird und mit dem ergebnis weiter gemacht wird.

j = ((j++) % (5));
bewirkt nicht das gleiche wie
j = ((++j) % (5));

:D
1
#include <stdio.h>
2
3
int main()
4
{
5
    int j=0;
6
    
7
    for(int i=0; i<10; i++) {
8
       j = ((j++) % (5));
9
        printf("%d\n",j);
10
    } 
11
    
12
    printf("\n");
13
    
14
    for(int i=0; i<10; i++) {
15
       j = ((++j) % (5));
16
        printf("%d\n",j);
17
    }
18
    
19
    printf("\n");
20
    
21
    for(int i=0; i<10; i++) {
22
       j = ((j+1) % (5));
23
        printf("%d\n",j);
24
    }
25
    
26
    return 0;
27
}

von timi16 (Gast)


Lesenswert?

at lkmiller
>> Was passiert wohl damit:
1
    for(int i=0; i<100; i++) {
2
3
        j = (j=j+1) % 5;
4
5
        printf("%d\n",j);
6
7
    }
8
]/code]
9
[code]
10
    for(int i=0; i<10; i++) {
11
12
       j = ((++j) % (5));
13
14
        printf("%d\n",j);
15
16
    }

Dieses beiden Schnippsel funktionieren so wie ich es erwarten würde.

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


Lesenswert?

timi16 schrieb:
> j = ((j++) % (5));
> bewirkt nicht das gleiche wie
> j = ((++j) % (5));
Gut so. Denn sonst wäre eines davon unnötig...

von EAF (Gast)


Lesenswert?

Lothar M. schrieb:
> BTW: Fehlen da nicht noch ein paar Klammern?

Nöö...
> warning: operation on 'j' may be undefined [-Wsequence-point]
Komma und Semikolon setzen sequence points.

Aber hier bewirken (überflüssige?) Klammern etwas:
if(a=b) ...
if((a=b)) ...

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


Lesenswert?

timi16 schrieb:
> Dieses beiden Schnippsel funktionieren so wie ich es erwarten würde.
Und was ist wenn du es ganz ohne Klammern probierst:
1
j = ++j % 5;
Sonst geht die Klammertaste so schnell kaputt...

EAF schrieb:
> Lothar M. schrieb:
>> BTW: Fehlen da nicht noch ein paar Klammern?
> Nöö...
Aber man könnte sicher noch ein paar drumrum machen  ;-)

: Bearbeitet durch Moderator
von FOp (Gast)


Lesenswert?

Sicher, dass das "undefined" ist ? Bei C ist so einiges festgelegt, was 
man der Verständlichkeit zuliebe besser lassen sollte.
Eine Warnung, dass Variablenwerte überschrieben werden, bevor sie 
benutzt werden gibt es IMHO nicht. Nur wenn der Wert in einer Variable 
nie genutzt wird oder wenn er gar genutzt wird, bevor er gesetzt wurde.

Dein Problem dürfte sein, dass Du das _Post_inkrement benutzt.

1) Hole den Wert von j
2) zähle j 1 hoch
3) berechne geholten Wert modulo 5
4) lade j mit berechneter Zahl

Damit ist Schritt 2 quasi für ein Körperteil Deiner Wahl. Mit 
_Pre_inkrement ginge es, weil dann Schritt 1 und 2 vertauscht wären.

von timi16 (Gast)


Lesenswert?

>> Gut so. Denn sonst wäre eines davon unnötig...

>>Aber hier bewirken (überflüssige?) Klammern etwas:
Ja absolut haben die klammern einen sinn :D
Der Ausdruck innerhalb der Klammer wird doch erstmal ausgeführt.

Ich kenne den unterschied zwischen ++j und j++! :D
++j: es wird erst inkrementiert dann zugewiesen oder operation gemacht,
j++: es wird erst die operation/zuweisung gemacht und dann 
inkrementiert.
Da ich den Ausdruck aber klammere dürfte sich der ausdruck auserhalb 
dser klammer gleich verhalten oder sehe ich das mit der klammerung 
flasch?

Ich würde vermuten das sie die ausdrücke aufgrund der klammerung gleich 
verhalten müssten: (++j), (j++) und j=(j+1)

von Peter D. (peda)


Lesenswert?

timi16 schrieb:
> Ich dachte das
> klammern bewirkt IMMER, dass ermal der Ausdruck in der klammer
> ausgeführt wird und mit dem ergebnis weiter gemacht wird.

Klammern, die an der Operatorrangfolge nichts ändern, bewirken auch 
nichts.

Der GCC ist da leider zu geschwätzig und warnt auch bei völlig korrekten 
Ausdrücken fehlende Klammern an, z.B. bei AND/OR.

von timi16 (Gast)


Lesenswert?

Danke euch :)

von Peter D. (peda)


Lesenswert?

timi16 schrieb:
> Da ich den Ausdruck aber klammere dürfte sich der ausdruck auserhalb
> dser klammer gleich verhalten oder sehe ich das mit der klammerung
> flasch?

Du erklärst erst die Unterschiede und erwartest aber, daß sie sich 
gleich verhalten. Hast Du Deine eigene Erklärung nicht verstanden?

timi16 schrieb:
> Ich würde vermuten das sie die ausdrücke aufgrund der klammerung gleich
> verhalten müssten: (++j), (j++) und j=(j+1)

Alle 3 machen jeweils etwas anderes. Daran kann man sie auch mit 1000 
Klammern nicht hindern.

von Programmierer (Gast)


Lesenswert?

timi16 schrieb:
> j = ((j++) % (5));
> bewirkt nicht das gleiche wie
> j = ((++j) % (5));

Doch, beides ist das Gleiche, nämlich FALSCH (undefined behaviour). Der 
Compiler kann da irgendwas draus machen.

FOp schrieb:
> Sicher, dass das "undefined" ist ?

Ja. Es ist kein Sequenzpunkt zwischen den Zuweisungen.

Die ganze Spekuliererei (auch von Moderatoren...) was das jetzt genau 
macht ist ziemlich sinnlos. Der Code ist schlicht Blödsinn, da passiert 
nichts irgendwie sinnvolles oder konsistentes. Der Compiler kann da ein 
Programm draus machen das einfach leer ist und nichts tut, was die 
Festplatte formatiert, sofort abstürzt, was auch immer. Beim nächsten 
Compiler-Update, beim Anpassen der Compiler-Optionen, Ändern irgendeines 
anderen Codeteils kann sich das Verhalten beliebig ändern. Man kann sich 
also Null darauf verlassen. Der Code muss also abgeändert werden.

von Dieter D. (dieter_dosenkohl)


Lesenswert?

Wenn jmd sagt er hat 20 Jahre Erfahrung und dann sowas macht: fristlose 
Kündigung.

von EAF (Gast)


Lesenswert?

timi16 schrieb:
>>>Aber hier bewirken (überflüssige?) Klammern etwas:
> Ja absolut haben die klammern einen sinn :D
> Der Ausdruck innerhalb der Klammer wird doch erstmal ausgeführt.

Zweifach falsch!
1.
Klammern bilden keine sequence points.

2.
if(a=b) ... // warning: suggest parentheses around assignment used as 
truth value [-Wparentheses]

if((a=b)) .. // Warnung unterbleibt
Die Klammern haben keine Auswirkungen auf die Verarbeitung, sind also 
aus der Sicht überflüssig.



Programmierer schrieb:
> Die ganze Spekuliererei (auch von Moderatoren...) was das jetzt genau
> macht ist ziemlich sinnlos. Der Code ist schlicht Blödsinn, da passiert
> nichts irgendwie sinnvolles oder konsistentes.

Ein UB ist und bleibt ein UB.
Eine Diskussion, über die Folgen eines UB sind recht irrational.
Denn die Folgen sind nicht vorhersagbar.
Es kann nur darum gehen, ein UB zu erkennen und auszumerzen.

von oder so (Gast)


Lesenswert?

timi16 schrieb:
> Ich bin voll überrascht. Ich kenne C seit 20 jahren und ich hätte
> gedacht das beide Schleifenschnippsel sich gleich verhalten.

"Ich denke seit 20 Jahren, dass ich C kenne..." trifft es wohl besser. 
:-)

von W.S. (Gast)


Lesenswert?

timi16 schrieb:
> Wieso liefern folgende schnippsel unterschiedliche ergebnisse?

Gegenfrage:
Wieso versuchst du krampfhaft, zwei verschiedene Funktionalitäten zu 
einem gordischen Knoten zu verknüpfen? Also die eigentliche Funktion und 
das Postinkrement?

Wenn du schon gemerkt hast, daß das je nach Schreibweise zu 
unterschiedlichen Ergebnissen führt, dann sollte dir eigentlich klar 
sein, daß man nicht jeden Kram auch machen muß. So ist es z.B. auch 
nicht verboten, aus dem Fenster zu springen - beim Bungalow ist das 
relativ egal, aber wenn's der zehnte Stock ist, dann sieht das Ergebnis 
etwas weniger angenehm aus.

Wenn du es ganz genau wissen willst, dann schau dir die Unterlagen zum 
konkreten Compiler gründlich an. Wenn du Fehlfunktionen vermeiden 
willst, dann schreibe dein Zeugs anders, so daß jeder Compiler daraus 
erkennen kann, was du eigentlich haben willst. Alles andere ist bloßes 
Herumjammern.

W.S.

von Klaus W. (mfgkw)


Lesenswert?

Man könnte auch einfach mal den Kernighan und Ritchie lesen.

von Bauform B. (bauformb)


Lesenswert?

Und es wird immer schlimmer, inzwischen ist es undefined, ob es 
undefined ist ;)
https://stackoverflow.com/questions/60937761/sequence-points-is-this-gcc-warning-a-bug
1
The GCC documentation states about the -Wsequence-point
2
warning flag (enabled by -Wall):
3
  The C++17 standard will define the order of evaluation of operands
4
  in more cases: in particular it requires that the right-hand side
5
  of an assignment be evaluated before the left-hand side, so the
6
  above examples are no longer undefined. But this option will still
7
  warn about them, to help people avoid writing code that is undefined
8
  in C and earlier revisions of C++.
Auf jeden Fall ein schönes Beispiel, warum man immer alle Warnungen 
einschaltet und wie Fehler behandelt.

von Cyblord -. (cyblord)


Lesenswert?

Klaus W. schrieb:
> Man könnte auch einfach mal den Kernighan und Ritchie lesen.

Was wissen die schon von C....

von Klaus W. (mfgkw)


Lesenswert?

Stimmt. Dann hieße er ja Cernighan.

von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

Die IAR Embedded Workbench für Arm v9.20.2 sagt mit den Default-Settings 
für Warnungen & Fehler zum ersten Code-Schnipsel:
1
Warning[Pa079]: undefined behavior: variable "j" (declared at line 8) (or a value reached by some form of indirection through it) is modified more than once without an intervening sequence point in this statement

Gruß,
Michael

von W.S. (Gast)


Lesenswert?

Ich predige ja schon seit langem, daß man besser fährt, wenn man seine 
Quellen eher "bieder" schreibt. Also für C-Programmierer: nicht jeden 
Furz benutzen, der nicht explizit verboten ist.
1
  i = 0;
2
  j = 0;
3
  while (i < 100)
4
  { j = (j+1) % 5;
5
    printf("%d\n",j);
6
    ++i;
7
  }

Das sieht zwar etwas länger aus, sollte aber von jeder Toolchain richtig 
verstanden werden. Und vom menschlichen Leser auch. Ob es jedoch das 
ist, was der TO zu bezwecken beabsichtigt, ist eine andere Frage.

W.S.

von Programmierer (Gast)


Lesenswert?

W.S. schrieb:
> Ich predige ja schon seit langem, daß man besser fährt, wenn man seine
> Quellen eher "bieder" schreibt.

Eine 0815-for-Schleife, die jeder Programmierer auf diesem Planeten in 
3µs sofort als Zählschleife (hier mit 100 Schritten) erkennt, durch eine 
while-Schleife zu ersetzen, bei der man erstmal genau schauen muss was 
sie tut, ist nicht bieder, sondern Obfuskation. for-Schleifen zu 
vermeiden ist das Bescheuerteste was ich seit Langem gelesen habe.

Übrigens ist eine Zählschleife mit fix vorgegebener Iterationszahl sogar 
in der theoretischen Informatik einfacher (LOOP-Programm) als 
While-Schleifen (WHILE-Programm); LOOP-Programme sind nichtmal 
Turing-Vollständig. Also ist die for-Schleife (zumindest in ihrer 
Ausprägung als Zählschleife) sogar "biederer".

Dass du dich selbst als Prediger siehst passt irgendwie - ewige 
Wiederholung aus den Fingern gesogener Ideen und Dogmen trotz Gegenwind 
passt.

W.S. schrieb:
> Das sieht zwar etwas länger aus, sollte aber von jeder Toolchain richtig
> verstanden werden.

Korrekter Code wird von allen Toolchains korrekt erkannt. Der Code vom 
TO ist aber undefined bevahiour, also blödsinniger Code. Den macht 
natürlich keine Toolchain irgendwas sinnvolles mit.

von Oliver S. (oliverso)


Lesenswert?

Bauform B. schrieb:
> Und es wird immer schlimmer, inzwischen ist es undefined, ob es
> undefined ist ;)

Ist es nicht.

> The C++17 standard

ist für C, um das es hier geht, völlig irrelevant.

Oliver

von EAF (Gast)


Lesenswert?

W.S. schrieb:
> Ich predige ja schon seit langem, daß man besser fährt, wenn man seine
> Quellen eher "bieder" schreibt.
Das ist ok....
Schlicht, flach, naiv... gibt es nichts gegen zu sagen.

Aber die for durch eine while zu ersetzen ist Schwachfug!
Ist in diesem Kontext absolut sinnfrei.
Hat mit dem Eingangsproblem auch nix zu tun.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Das sieht zwar etwas länger aus, sollte aber von jeder Toolchain richtig
> verstanden werden.

Und man kann es problemlos auf andere Programmiersprachen portieren.

von Programmierer (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Und man kann es problemlos auf andere Programmiersprachen portieren.

Die meisten Programmiersprachen können for-Schleifen. In funktionalen 
Programmiersprachen sind While-Schleifen tendentiell unpassender!

von EAF (Gast)


Lesenswert?

Tipp, in Sachen Naivität:
> j = ((j++) % (5));
Es tut keine Not alles ganz verbissen in eine Zeile zu quetschen zu 
wollen.
1
for(int i=0,j=0;i<100;i++,j++,j%=5,Serial.println(j)) {;}

von Egon D. (Gast)


Lesenswert?

Klaus W. schrieb:

> Man könnte auch einfach mal den Kernighan und Ritchie
> lesen.

Man könnte auch eine Portion Bratkartoffeln essen. Das
verbessert den Programmierstil in C wahrscheinlich mehr
als die Lektüre des K&R...

SCNR

von Egon D. (Gast)


Lesenswert?

W.S. schrieb:

> Ich predige ja schon seit langem, daß man besser fährt,
> wenn man seine Quellen eher "bieder" schreibt.

Kommt auf das genaue Ziel an.

Für den, der nur notgedrungen programmiert, weil er
korrekt funktionierende Programme benötigt, ist das
ein guter Rat.

Wer aber anderen stets und ständig die eigene
Großartigkeit unter die Nase reiben muss, fährt
natürlich schlecht mit einem "Anfänger-Stil"...

von Programmierer (Gast)


Lesenswert?

Egon D. schrieb:
> Für den, der nur notgedrungen programmiert, weil er
> korrekt funktionierende Programme benötigt, ist das
> ein guter Rat.

Naja, man sollte auch Anfängern direkt einen guten Stil beibringen, 
angefangen bei der Einrückung, denn solche Gewohnheiten ändert man nicht 
mehr. Dass nicht jeder alle Sprachelemente benutzen muss ist klar; aber 
solche absoluten Basics wie die for-Schleife sollte jedem bekannt sein. 
C kann ja sowieso kaum was, außer einer Handvoll Gemeinheiten wie goto, 
Multithreading, setjmp kann man schon das meiste angemessen einsetzen.

In anderen Sprachen gibt es viel mehr nützliche Konstrukte, die viel 
mehr machen als eine for-Schleife, aber auch für 
Gelegenheitsprogrammierer extrem nützlich sind. Spontan fallen mir da 
Generator-Expressions in Python ein.

von EAF (Gast)


Lesenswert?

Programmierer schrieb:
> außer einer Handvoll Gemeinheiten wie goto,

Auch goto hat seine sinnvollen Einsatzzwecke.
Goto hat seinen Ruf aus alten Basic/Fortran Zeiten.

Kein Sprachmittel ist per se böse oder gemein.
Natürlich kann man mit jedem Sprachmittel Mist bauen.
Aber das spricht nicht gegen das Sprachmittel.

von Programmierer (Gast)


Lesenswert?

EAF schrieb:
> Auch goto hat seine sinnvollen Einsatzzwecke.

Das stimmt, aber das sind nicht unbedingt die Dinge die man einen 
Gelegenheitsprogrammierer machen lassen sollte. Oder man lässt ihn eine 
andere Sprache wie Python nutzen, in der sich das jeweilige Problem 
sowieso ganz anders angehen lässt.

von EAF (Gast)


Lesenswert?

Programmierer schrieb:
> die man einen
> Gelegenheitsprogrammierer machen lassen sollte

Wer ist gleich noch der Bestimmer?
Du?
W.S?
Ich?
Oder wer?

Deine Aussagen sind teilweise korrekt und zielführend, aber teilweise 
auch ausufernd arrogant und anmaßend.

Den richtigen Umgang mit z.B. Goto, kann man nur "erfahren", wenn man 
den Umgang damit übt. Das im Vorfeld schon auszuschließen ist 
überzogen/irrational.

von W.S. (Gast)


Lesenswert?

EAF schrieb:
> Den richtigen Umgang mit z.B. Goto, kann man nur "erfahren",...

Naja, heutzutage wird gerade von C-Programmierern gern vergessen, daß 
das Wettern gegen 'goto' eigentlich nur eine damalige Polemik gegen die 
BASIC-Programmierer war. Damals war auf eigentlich jedem Homecomputer 
ein residentes BASIC drauf und dort war das 'goto' schlichtweg 
unverzichtbar. Deshalb waren so ziemlich alle Leute daran gewöhnt.

Und das von mir gepredigte 'biedere' Programmieren als Stil von 
Gelegenheits-Programmierern oder Anfängern zu bezeichnen, ist 
schlichtweg unklug. Denn wer da meint, daß er sich damit brüsten muß, 
daß er Kniffe kennt, an die ein anderer noch nicht gedacht hat, der ist 
lediglich ein Angeber, der insgesamt mehr Schaden anrichtet, als er sich 
je gedacht hat. Siehe dieser Thread. Wenn der TO seine Quelle einfach 
und bieder formuliert hätte, dann wäre er damit nicht auf die Nase 
gefallen und dieser Thread wäre völlig überflüssig gewesen.


Nochwas zu den Bemerkungen zur for-Schleife: Woanders ist so eine 
Schleife eben auch bieder und einfach verständlich gehalten:
 for i:= 0 to 99 do
 begin
   ...
 end

Nur in C ist das aufgeblähter. Ich mag derartige Aufgeblähtheit nicht.
Aber um die Schleifenbildung ging es hier ja überhaupt nicht.
Eigentlich.

W.S.

von Programmierer (Gast)


Lesenswert?

EAF schrieb:
> Den richtigen Umgang mit z.B. Goto, kann man nur "erfahren", wenn man
> den Umgang damit übt. Das im Vorfeld schon auszuschließen ist
> überzogen/irrational.

Logisch. Aber wer nur gelegentlich kleine Sachen mit möglichst wenig 
Aufwand umsetzen will, nutzt durch das Üben von goto seine Zeit nicht 
effizient.

W.S. schrieb:
> Denn wer da meint, daß er sich damit brüsten muß,
> daß er Kniffe kennt, an die ein anderer noch nicht gedacht hat, der ist
> lediglich ein Angeber, der insgesamt mehr Schaden anrichtet, als er sich
> je gedacht hat.

Du gibst doch ständig an, was du alles für tolle Verrenkungen machst, um 
vermeintliche Probleme von C oder auch Controllern zu umgehen, die man 
auch lösen könnte, indem man die jeweilige Technologie mal lernen würde.

W.S. schrieb:
> Wenn der TO seine Quelle einfach
> und bieder formuliert hätte, dann wäre er damit nicht auf die Nase
> gefallen und dieser Thread wäre völlig überflüssig gewesen.

Der Code war schlicht kein gültiges C. Mit bieder oder nichts hat das 
nichts zu tun.

W.S. schrieb:
> Nur in C ist das aufgeblähter. Ich mag derartige Aufgeblähtheit nicht.

Die for-Schleife in C und vielen anderen Sprachen ist universell 
gehalten, um mit möglichst wenig Sprachmitteln möglichst viel zu 
schaffen. Also durchaus bieder.

Eine in die Sprache integrierte Zählschleife hingegen ist komplexer, 
weil sie mehr Unterstützung vom Compiler braucht. Also überhaupt nicht 
bieder. Viele Sprachen unterstützen das, was auch gut ist, aber C sollte 
halt möglichst primitiv sein.

W.S. schrieb:
> Aber um die Schleifenbildung ging es hier ja überhaupt nicht.

Warum fängst du dann ungefragt damit an?

von A. S. (Gast)


Lesenswert?

EAF schrieb:
> Den richtigen Umgang mit z.B. Goto, kann man nur "erfahren", wenn man
> den Umgang damit übt. Das im Vorfeld schon auszuschließen ist
> überzogen/irrational.

Genau!

Ein Goto ist da sinnvoll, wenn der Code ohne Goto schlechter ist. Und 
das ist bei Anfängern häufiger so.

Ich habe schon langjährige Programmierer wegen Misra gotos ersetzen 
sehen: Durch das while(1)-Äquivalent mit switch/case. Das ist noch 
schlimmer als while statt for hier im Thread.

Gotos sind nicht böse. Sondern harmful und es gibt Alternativen.

von Peter D. (peda)


Lesenswert?

A. S. schrieb:
> Durch das while(1)-Äquivalent mit switch/case.

Genau das geht eben nicht. Das "while" läßt sich nur über "if" bedingt 
verlassen, da das "break" nur aus dem "switch" springt. Die 
Doppelbelegung des "break" hat mich schon oft geärgert.

von Klaus S. (kseege)


Lesenswert?

W.S. schrieb:
> Und das von mir gepredigte 'biedere' Programmieren als Stil von
> Gelegenheits-Programmierern oder Anfängern zu bezeichnen, ist
> schlichtweg unklug.

Wenn man wenig Zeit hat und ein sinnvolles Programm auf die Beine 
stellen will, stimme ich zu 300% zu.

Aber die ganzen tollen Hahnenkämpfe wie in diesem Thread gäbs nicht, der 
"obfuscated C contest" wäre ohne Inhalt und wir Zuschauer hätten nix zum 
Lachen, das ist ja wohl nicht erstrebenswert.

Gruß Klaus (der soundsovielte)

Disclaimer: Real programmers can do FORTRAN programs in every language.

von Egon D. (Gast)


Lesenswert?

W.S. schrieb:

> Und das von mir gepredigte 'biedere' Programmieren
> als Stil von Gelegenheits-Programmierern oder
> Anfängern zu bezeichnen, [...]

Ich hatte das "Anfänger" wohlweislich in Anführungs-
zeichen gesetzt -- wohl wissend, dass diese bald dem
Vergessen anheim fallen würden...


>  for i:= 0 to 99 do
>  begin
>    ...
>  end
>
> Nur in C ist das aufgeblähter.

Das ist kein sinnvoller Vergleich, denn "for" hat in
Pascal und in C nicht exakt die gleiche Bedeutung.

von Peter D. (peda)


Lesenswert?

P.S.:
Aus "while" mit "switch" heraus geht nur über "goto" oder "return".

von Egon D. (Gast)


Lesenswert?

Programmierer schrieb:

> Der Code war schlicht kein gültiges C. Mit bieder
> oder nichts hat das nichts zu tun.

Doch, natürlich: Wenn man hübsch und bieder das
nacheinander hinschreibt, was nacheinander ausgeführt
werden soll, gibt es in der Regel keine Probleme. Der
Ärger geht erst mit "...kann man auch kürzer schreiben
als..." los.
Da kommt dann auch schnell mal etwas heraus, was zwar
für den Laien so aussieht wie C, aber keins ist.

von Egon D. (Gast)


Lesenswert?

Klaus S. schrieb:

> Aber die ganzen tollen Hahnenkämpfe wie in diesem
> Thread gäbs nicht, der "obfuscated C contest" wäre
> ohne Inhalt und wir Zuschauer hätten nix zum Lachen,
> das ist ja wohl nicht erstrebenswert.

Ich verstehe den Sarkasmus, aber m.E. unterschätzt
Du das Problem. Welches C-Lehrbuch quillt nicht über von
Formulierungen wie "...kann kürzer geschrieben werden
als..." oder "...können hier auch weggelassen werden.."?

Da steckt eine ganze Lehr- und Denktradition dahinter:
Nur Anfänger und Versager schreiben zuviel hin.

Welchen rational nachvollziehbaren Sinn hat es, die
geschweiften Klammern bei EINER Anweisung im "then"-Zweig
wegzulassen, wenn man sie bei ZWEI oder mehr Anweisungen
ohnehin hinschreiben muss? Keinen! -- Aber es gilt als
Nachweis, dass man die Sprache behrrscht.

Wenn dann bei Änderungen Fehler entstehen, naja, Pech
gehabt... Kollateralschaden.

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Programmierer schrieb:
> Eine 0815-for-Schleife, die jeder Programmierer auf diesem Planeten in
> 3µs sofort als Zählschleife (hier mit 100 Schritten) erkennt,
Wo bleibst denn da der Spass wenn man einfach nur das notwendigste 
hinschreiben würde:-)
1
  for (int i = 1; i <= 100; ++i)
2
  {
3
    printf("%d\n", i%5);
4
  }

von Mombert H. (mh_mh)


Lesenswert?

Irgend W. schrieb:
> for (int i = 1; i <= 100; ++i)

Vorsicht! Die Definition von i in der Schleife ist für viele hier sicher 
schon zu modern und Komplex.

von Stefan F. (Gast)


Lesenswert?

Programmierer schrieb:
> Die meisten Programmiersprachen können for-Schleifen. In funktionalen
> Programmiersprachen sind While-Schleifen tendentiell unpassender!

Mir ging es nicht um die Schleife, sondern die Kombination aus Zuweisung 
und Post-Inkrement in einer Zeile.

von EAF (Gast)


Lesenswert?

Mombert H. schrieb:
> Die Definition von i in der Schleife ist für viele hier sicher
> schon zu modern und Komplex.

Aua!
Und mit C++ setzt dann die totale Überforderung ein?!?
1
  for(auto data:{3,7,42,6,4711}) Serial.println(data);

von Egon D. (Gast)


Lesenswert?

Mombert H. schrieb:

> Irgend W. schrieb:
>> for (int i = 1; i <= 100; ++i)
>
> Vorsicht! Die Definition von i in der Schleife ist
> für viele hier sicher schon zu modern und Komplex.

Das ist weder modern noch komplex, sondern der notdürftige
Versuch eines Ausgleichs uralter Defizite.

von Egon D. (Gast)


Lesenswert?

EAF schrieb:

> Und mit C++ setzt dann die totale Überforderung ein?!?
>
>   for(auto data:{3,7,42,6,4711}) Serial.println(data);

Das ist nur eine hässlichere Schreibweise für
1
foreach line {3,7,42,6,4777} { 
2
  puts $SIO $line 
3
}

von Oliver S. (oliverso)


Lesenswert?

EAF schrieb:
> Mombert H. schrieb:
>> Die Definition von i in der Schleife ist für viele hier sicher
>> schon zu modern und Komplex.
>
> Aua!

Die feinen Ironie der Aussage ist dir wohl entgangen. Die war auch 
wirklich arg versteckt ;)

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mombert H. schrieb:
> Vorsicht! Die Definition von i in der Schleife ist für viele hier sicher
> schon zu modern und Komplex.

Am wenigstens komplex (ohne Variablen und damit ohne Zuweisungen, ohne
explizite Schleife, ohne Rechenoperationen, ohne Verschachtelungen und
fast ohne Klammern) lässt sich das Beispiel immer noch in Haskell
schreiben:
1
main = mapM_ print $ take 100 $ cycle [0..4]

Da steht (in Programmiersprachensyntax) ganz einfach:

"Gib die ersten 100 Werte der zyklischen Zahlenfolge von 0 bis 4 aus."

:)

von Klaus S. (kseege)


Lesenswert?

Egon D. schrieb:
> Ich verstehe den Sarkasmus, aber m.E. unterschätzt
> Du das Problem.

Ich habe mein ganzes Berufsleben davon profitiert, daß die versammelten 
Dummbattel irgendwas nicht hingekriegt haben, ich aber wohl. Das lag 
daran, daß ich langsamer war, nicht schneller oder klüger. Insofern habe 
ich immer von diesem Problem gelebt. It made my life!!!

Gruß Klaus (der soundsovielte)

von Oliver S. (oliverso)


Lesenswert?

Echtes C ist halt C, und nicht Fortran, Pascal, oder was auch immer.

Ausschnitt aus malloc.c der avr-libc:
1
  for (s = 0, fp1 = __flp, fp2 = 0;
2
       fp1;
3
       fp2 = fp1, fp1 = fp1->nx) {

So geht das, und nicht anders.

Oliver

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Oliver S. schrieb:
> Ausschnitt aus malloc.c der avr-libc

Das ist wieder so eine Stelle wo ich mir denke: Eigentlich sollten die 
Standard Bibliotheken als Vorbild für guten Programmierstil gelten. Das 
hier ist jedoch das Gegenteil davon.

Ebenso finde ich einfach nur furchtbar, wie cout die Operator-Überladung 
missbraucht, anstatt "sprechende" Methoden-Namen.

von EAF (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das ist wieder so eine Stelle wo ich mir denke: Eigentlich sollten die
> Standard Bibliotheken als Vorbild für guten Programmierstil gelten. Das
> hier ist jedoch das Gegenteil davon.

Seltsame Anforderungen, du hast...

Wenn du gesagt hättest:
"Standard Bibliotheken können als Vorbild für effizienten Code gelten"
"Standard Bibliotheken können als Vorbild für portablen Code gelten"
Dann würde ich das halbwegs verstehen.

Aber eigentlich ist der Code Standard Bibliotheken recht uninteressant, 
solange er denn das tut, was die Doku verspricht.
Das Interface, damit haben wir es zu tun.

Das hat alles nichts damit zu tun, ob ich die konkrete Schleife als 
schön empfinde, oder auch nicht.

Stefan ⛄ F. schrieb:
> Ebenso finde ich einfach nur furchtbar, wie cout die Operator-Überladung
> missbraucht, anstatt "sprechende" Methoden-Namen.

Furchtbar, ganz furchtbar.

von Stefan F. (Gast)


Lesenswert?

EAF schrieb:
> Furchtbar, ganz furchtbar.

Ja schlimm. Alles geht den Bach runter. Früher war mehr Lametta.

von A. S. (Gast)


Lesenswert?

Peter D. schrieb:
> Genau das geht eben nicht. Das "while" läßt sich nur über "if" bedingt
> verlassen, da das "break" nur aus dem "switch" springt. Die
> Doppelbelegung des "break" hat mich schon oft geärgert.

Eine Programmierer hatte jede Menge Gotos verwendet. Als ein Auditor das 
bemängelte, wurden alle Gotos durch besagtes Äquivalent beseitigt. Finde 
ich grad nicht, ist wohl Standard, geht wie im Beispiel unten. Der Code 
kann stumpf so stehen bleiben, die Sprungmarken werden durch Zahlenwerte 
ersetzt, ein int als Switch und statt goto dann neustart mit neuem Wert. 
Selbst das springen in und aus Klammern ist (analog Duffs Device) 
möglich. Du kannst also einen Programmierer 100 Gotos die Stunde 
ersetzen lassen, reine Textersetzung + Klammer drumrum.

Der absolute Obfustacle-Horror. Vor allem, wenn man nicht weiß, was das 
soll und kein VCS hat, mit dem man "das Muster" erkennt.
1
LABEL_1: 
2
   ... (do stuff) ...;
3
4
5
LABEL_2: 
6
   ... (do stuff) ...;
7
   ... if(...) goto LABEL_3;
8
         
9
LABEL_3: 
10
   ... (do stuff) ...;
11
   ... if(...) goto LABEL_1;
wird zu:
1
int label=1;
2
3
   while(label) switch(label)
4
   {
5
   
6
   case 1: ... (do stuff) ...;
7
   
8
   case 2: ... (do stuff) ...;
9
           ... if(...) {label=3; break;}
10
         
11
   case 3: ... (do stuff) ...;
12
           ... if(...) {label=1; break;}
13
14
    label=0;
15
   }

(Oh, falls es Dir um while(1) geht, dass wurde anfangs verwendet und 
hinter dem switch noch ein if(label) gesetzt. Alter C-Compiler, so 
konnte label im while gekapselt bleiben)

von Mombert H. (mh_mh)


Lesenswert?

Egon D. schrieb:
> Mombert H. schrieb:
>> Irgend W. schrieb:
>>> for (int i = 1; i <= 100; ++i)
>> Vorsicht! Die Definition von i in der Schleife ist
>> für viele hier sicher schon zu modern und Komplex.
> Das ist weder modern noch komplex, sondern der notdürftige
> Versuch eines Ausgleichs uralter Defizite.
Magst du auch noch erklären, was du hier als "uralte Defizite" ansiehst?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Stefan ⛄ F. schrieb:
> Oliver S. schrieb:
>> Ausschnitt aus malloc.c der avr-libc
>
> Das ist wieder so eine Stelle wo ich mir denke: Eigentlich sollten die
> Standard Bibliotheken als Vorbild für guten Programmierstil gelten. Das
> hier ist jedoch das Gegenteil davon.

Ich finde das völlig in Ordnung. Ohne den Kontext zu kennen, sieht man
sofort, dass da eine verkettete Liste namens _flp durchwandert wird. Der
Übersichtlichkeit halber sind sogar die Ausdrücke für Initialisierung,
Abbruchprüfung und Aktualisierung der Laufvariablen auf drei Zeilen
verteilt.

Nur der Zweck von s ist aus diesem kurzen Codeausschnitt nicht direkt
ersichtlich, da die Variable zwar initialisiert, aber im Schleifenkopf
nicht verwendet wird. Aber auch das wird sofort klar, wenn man den
Schleifenrumpf betrachtet.

Darüberhinaus wird die Funktion der Schleife auch noch in einem
ausführlichen Kommentar über der Schleife erklärt.

Was sollte deiner Meinung noch zusätzlich getan werden, um den Code
für dich verständlicher zu machen?


Stefan ⛄ F. schrieb:

> Ebenso finde ich einfach nur furchtbar, wie cout die Operator-Überladung
> missbraucht, anstatt "sprechende" Methoden-Namen.

Finde ich auch, nicht nur wegen des Missbrauchs der Bitshift-Operatoren,
sondern vor allem wegen der totalen Unübersichtlichkeit bei etwas
komplexeren Formatierungen. Die Format-Library von C++20 behebt aber
beides weitgehend. Leider ist sie noch nicht in allen Tool-Chains
implementiert.

von Sebastian (Gast)


Lesenswert?

Egon D. schrieb:
> Das ist nur eine hässlichere Schreibweise für
> foreach line {3,7,42,6,4777} {
>   puts $SIO $line
> }

Wenn das Tcl sein soll dann aber Leerzeichen statt Komma ...

LG, Sebastian

von Egon D. (Gast)


Lesenswert?

Sebastian schrieb:

> Egon D. schrieb:
>> Das ist nur eine hässlichere Schreibweise für
>> foreach line {3,7,42,6,4777} {
>>   puts $SIO $line
>> }
>
> Wenn das Tcl sein soll dann aber Leerzeichen statt Komma ...

Das darf nicht wahr sein. Tatsache. Mea culpa, mea maxima
culpa...


Und -- ja, das sollte Tcl sein.

von Egon D. (Gast)


Lesenswert?

Mombert H. schrieb:

> Magst du auch noch erklären, was du hier als "uralte
> Defizite" ansiehst?

Der einzige durchmusterbare Datentyp, den die Sprache kennt,
ist das Array, und die Sprache unterstützt freiwillig auch
nur den Zugriff auf die Elemente über deren Index. Mitlaufende
Pointer kann man zwar verwenden, aber das muss man alles von
Hand organisieren.

Das führt zu völlig sinnloser Doppelarbeit, weil man in der
for-Schleife in der Regel den Index i laufen lässt -- vor
jedem Zugriff muss aber mittels a[i] erstmal der zugehörige
Pointer ausgerechnet werden. Irgendwas der Bauart...
1
for value:=a[20] to a[100] do { ... }
...geht nicht.

Typische Mathematiker-Denke halt. Ist aber in Pascal genauso.


Scriptsprachen beweisen, dass es deutlich besser geht:
1
foreach line $inlist { ... }

Tcl kennt überhaupt keine Pointer, und man braucht auch keine
Pointer -- und eine Laufvariable ist zum Durchmustern genauso
wenig notwendig.


Und nur für den Fall: Das ist keine Kritik an C. Eher eine
Kritik daran, minimale Kosmetik als "modern und komplex" zu
bezeichnen...

von Rolf M. (rmagnus)


Lesenswert?

Egon D. schrieb:
> Der einzige durchmusterbare Datentyp, den die Sprache kennt,
> ist das Array, und die Sprache unterstützt freiwillig auch
> nur den Zugriff auf die Elemente über deren Index.

Eigentlich nicht. Die Sprache unterstützt nur Pointer-Arithmetik zum 
Zugriff. Die Index-Schreibweise ist nur syntaktischer Zucker dafür. 
Anders gesagt: a[i] ist zu 100% äquivalent zu *(a+i). Das geht sogar 
soweit, dass man statt a[i] auch i[a] schreiben kann (also "Hallo"[3] 
und 3["Hallo"] das gleiche ist), weil die Addition kommutativ ist.

> Mitlaufende Pointer kann man zwar verwenden, aber das muss man alles von
> Hand organisieren.

Was verstehst du unter "von Hand organisieren"? Der Pointer ist in dem 
Zusammenhang letztendlich das, was man in anderen Sprachen generalisiert 
als Iterator kennt. In C++ können Pointer auch als Iteratoren verwendet 
werden.

Egon D. schrieb:
> Das führt zu völlig sinnloser Doppelarbeit, weil man in der
> for-Schleife in der Regel den Index i laufen lässt

Man kann da genauso gut einen Pointer laufen lassen, ganz ohne Index. 
Und bei verketteten Listen gibt's gar keinen Index, aber da kann man 
sowas schreiben:
1
for (element* elem = list.start; elem; elem = elem->next)

> Irgendwas der Bauart...for value:=a[20] to a[100] do { ... }
> ...geht nicht.

Vielleicht verstehe ich dich falsch, aber wäre das nicht sowas?
1
for (int* p = &a[20]; p != &a[100]; ++p)
2
    printf("%d\n", *p);

: Bearbeitet durch User
von Justin S. (Gast)


Lesenswert?

timi16 schrieb:
> Ich kenne C seit 20 jahren und ich hätte
> gedacht das beide Schleifenschnippsel sich gleich verhalten.

Zum Glück "kennst" Du C nur und programmierst nichts. Sonst müsstest Du 
ja jetzt Deine gesamten Elaborate der letzten 20 Jahre durchsehen?!

Und stelle Dir bitte mal vor, es gebe noch mehr so "überraschende" Dinge 
in C und Du würdest sie auch nicht kennen. Vielleicht doch zunächst mal 
den K&R komplett lesen?

von Stefan F. (Gast)


Lesenswert?

Yalu X. schrieb:
> Was sollte deiner Meinung noch zusätzlich getan werden, um den Code
> für dich verständlicher zu machen?

Nicht so viel in eine Zeile packen. Dann liest es sich leichter.

von Mombert H. (mh_mh)


Lesenswert?

Stefan ⛄ F. schrieb:
> Yalu X. schrieb:
>> Was sollte deiner Meinung noch zusätzlich getan werden, um den Code
>> für dich verständlicher zu machen?
> Nicht so viel in eine Zeile packen. Dann liest es sich leichter.
An dieser Stelle frage ich mich ernsthaft, ob du in der Lage bist eine 
Buch oder eine Zeitung zu lesen. Da stehen gewöhnlich auch mehr als 5 
Wörter in einer Zeile.

von Rolf M. (rmagnus)


Lesenswert?

Mombert H. schrieb:
> Stefan ⛄ F. schrieb:
>> Yalu X. schrieb:
>>> Was sollte deiner Meinung noch zusätzlich getan werden, um den Code
>>> für dich verständlicher zu machen?
>> Nicht so viel in eine Zeile packen. Dann liest es sich leichter.
> An dieser Stelle frage ich mich ernsthaft, ob du in der Lage bist eine
> Buch oder eine Zeitung zu lesen.

Gerade in Zeitungen werden die Artikel bewusst auf mehrere Spalten 
verteilt, damit die Zeilen kurz und einfacher lesbar sind.
Wobei bei dem obigen Beispiel vielleicht "Zeile" durch "Anweisung" zu 
ersetzen ist. Da wird viel zu viel in den Schleifen-Kopf gepackt. Dass 
das auf drei Zeilen verteilt wurde, macht's dann auch nicht mehr 
wirklich besser.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Stefan ⛄ F. schrieb:
> Yalu X. schrieb:
>> Was sollte deiner Meinung noch zusätzlich getan werden, um den Code
>> für dich verständlicher zu machen?
>
> Nicht so viel in eine Zeile packen. Dann liest es sich leichter.

Die längste der drei ist gerade mal 33 Zeichen (inkl. Leerzeichen) lang,
und der Autor hat die drei Bestandteile des Schleifenkopfs auf in 
einzelne
Zeilen aufgeteilt:
1
for (s = 0, fp1 = __flp, fp2 = 0;
2
     fp1;
3
     fp2 = fp1, fp1 = fp1->nx) {

Noch weniger pro Zeile würde bspw. so aussehen:
1
for (
2
  s = 0,
3
  fp1 = __flp,
4
  fp2 = 0;
5
  fp1;
6
  fp2 = fp1,
7
  fp1 = fp1->nx) {

Besser? ;-)

Rolf M. schrieb:
> Da wird viel zu viel in den Schleifen-Kopf gepackt.

So hat das wahrscheinlich auch Stefan gemeint.

> Dass das auf drei Zeilen verteilt wurde, macht's dann auch nicht mehr
> wirklich besser.

Nachdem ich noch einmal etwas darüber nachgedacht habe, würde ich die
Initialisierung von s aus dem Schleifenkopf herausnehmen, weil sie nicht
so richtig dorthin passt. fp1 und fp2 hingegen durchlaufen beide (um
einen Listenknoten versetzt) die Liste und sind damit Laufvariablen. Als
solche sind deren Initialisierung und Weiterschaltung IMHO sehr gut im
Schleifenkopf aufgehoben:
1
s = 0;
2
for (fp1 = __flp, fp2 = 0;
3
     fp1;
4
     fp2 = fp1, fp1 = fp1->nx) {

von Oliver S. (oliverso)


Lesenswert?

Wobei man drüber diskutieren kann, die fp2-Behandlung in den 
Schleifenrumpf zu legen.

Und dann noch etwas umbenennen, und man landet bei

Rolf M. schrieb:
> for (element* elem = list.start; elem; elem = elem->next)

Oliver

von W.S. (Gast)


Lesenswert?

Egon D. schrieb:
> Das ist kein sinnvoller Vergleich, denn "for" hat in
> Pascal und in C nicht exakt die gleiche Bedeutung.

Tja, sowohl Pascal als auch C haben eine 'for'-Anweisung. Und die ist 
eigentlich dazu gedacht, für eine abgezählte Anzahl von Dingen dasselbe 
zu tun. Wenn in C das nun aufgebläht wurde, um nicht nur Aufzählungen, 
sondern auch diverse andere Dinge damit zu tun, ist das nicht das 
Problem der eigentlichen 'for'-Anweisung, sondern das Problem der 
C-Programmierer, die es so wollen.

Etwa so ähnlich sehe ich die diversen Bemühungen, sich um ein sinnvolles 
'goto' herumzudrücken, wie z.B. for(;;;) oder so und while(true) und 
Konsorten. Ich übersetze mir das so: warum einfach, wenn es auch 
kompliziert geht?

Bei C-Leuten sehe ich immer wieder die Bemühung, die Dinge 
zweckzuentfremden. Da werden Anweisungen verkompliziert, um auch 
exotische Programmierer-Ideen zu ermöglichen (die bei gründlicherem 
Nachdenken völlig überflüssig wären), verschiedene Anweisungen 
zusammengezogen (siehe dieser Thread) oder sonstiger Unfug getrieben, 
bloß aus purem Mutwillen. Der letzte Schrei war 'weak', was eigentlich 
niemals aus der Assembler-Ebene hätte heraus gedurft hätte. Bloß weil 
die Cortex-Controller und die zugehörigen Linker das gebraucht haben. 
Und schon grübeln die C-Leute darüber, was man daraus in C noch weiter 
machen kann.

Irgendwie erscheint mir das alles wie das Streben, auf der Rasierklinge 
zu reiten. Und anstatt mal wieder runter zu kommen auf eine rationale 
Ebene, wird hier inzwischen über sowas diskutiert:
> s = 0;
> for (fp1 = __flp, fp2 = 0;
>      fp1;
>      fp2 = fp1, fp1 = fp1->nx) {

Geht's noch?

W.S.

von Stefan F. (Gast)


Lesenswert?

Mombert H. schrieb:
>> Nicht so viel in eine Zeile packen. Dann liest es sich leichter.
> An dieser Stelle frage ich mich ernsthaft, ob du in der Lage bist eine
> Buch oder eine Zeitung zu lesen.

Ich habe nicht gesagt, dass ich diese Zeile nicht verstehe. Zwischen 
"liest sich leichter" und "verstehe ich nicht" besteht ein großer 
Unterschied.

Ich arbeite täglich an Programmen, die einige hundert tausend bis etwas 
über eine Millionen Zeilen Quelltext (nicht Leerzeichen/Kommentare) 
enthalten. Solche stellen wie die bemängelte sind, an denen ich beim 
Lesen in Stocken gerate.

Dein Vergleich mit Bücher/Zeitungen ist trotzdem nicht schlecht, denn 
auch dort tue ich mich ab einer Gewissen Satzlänge tatsächlich schwer, 
den Text zu verstehen. Allerdings nicht schon ab 5 Wörtern.

von Programmierer (Gast)


Lesenswert?

W.S. schrieb:
> Bei C-Leuten sehe ich immer wieder die Bemühung, die Dinge
> zweckzuentfremden.

C an sich ist zweckentfremdet. Das ist eigentlich eine minimalistische 
Sprache für System-Programmierung, aber die Leute benutzen es für alles 
mögliche. Die for-Schleife in C ist so wie sie ist weil man so mit 
primitiven Compilern viel machen kann. Die war nie für besonders elegant 
strukturierte Programme gemacht. Wenn du gute Schleifen-Konstrukte sehen 
willst, schau dir Kotlin, Python, Scala an. Das braucht aber auch viel 
komplexere Logik im Compiler...

Der Vorteil der for-Schleife ist, dass man die Logik der Schleife auf 
einen Blick sieht (Initialisierung, Laufbedingung, Post-Anweisung), 
statt sich durch eine lange while-Schleife durchwühlen zu müssen. Und 
das kann man eben für Zählschleifen, Iterieren von Arrays und 
verketteten Listen usw. nutzen ohne dass da eine komplexe Maschinerie im 
Hintergrund sitzen muss.

W.S. schrieb:
> er letzte Schrei war 'weak', was eigentlich
> niemals aus der Assembler-Ebene hätte heraus gedurft hätte.

Das ist auch nicht im C-Standard sondern eine Erweiterung.

W.S. schrieb:
> Bloß weil
> die Cortex-Controller und die zugehörigen Linker das gebraucht haben.

Das hat nichts mit Cortex zu tun, das wird auf anderen Plattformen auch 
benutzt. Für sowas wie Interrupt-Vektoren ist es ein probates Mittel, 
auf Anwendungsebene hat das nichts zu suchen. Dass irgendwelche Leute 
das zweckentfremden heißt nicht dass die Sprache an sich schlecht ist.

von Yalu X. (yalu) (Moderator)


Lesenswert?

W.S. schrieb:
> Tja, sowohl Pascal als auch C haben eine 'for'-Anweisung. Und die ist
> eigentlich dazu gedacht, für eine abgezählte Anzahl von Dingen dasselbe
> zu tun.

Dafür ist sie in Pascal gedacht bzw. darauf eingeschränkt. In C ist
die For-Schleife dafür gedacht, über irgendetwas zu iterieren. Dieses
Irgendetwas kann – wie in Pascal – ein Bereich von Zahlenwerten oder
Enums sein, aber bspw. auch eine verkettete Liste oder ein anderer
sequentieller Datentyp. Deswegen wird in C aus der Zählvariable
in Pascal eine Laufvariable.

Man kann in C auch numerisch nichtlinear iterieren, bspw. über
Zehnerpotenzen:
1
for (p = 1; p <= 1000000; p *= 10)

Da hat Kernighan halt einfach etwas weiter gedacht als Wirth.

Natürlich ist auch die For-Schleife in C nicht der Weisheit letzter
Schluss, aber sie stellt zumindest eine sinnvolle Verallgemeinerung der
reinen Zählschleife dar.

> Etwa so ähnlich sehe ich die diversen Bemühungen, sich um ein sinnvolles
> 'goto' herumzudrücken, wie z.B. for(;;;) oder so und while(true) und
> Konsorten.

Weil es in Pascal keine bedingungslosen Schleifen gibt, und du
Dummy-Bedingung (wie in whilte(true)) ablehnst, bist du gezwungen, auf
goto auszuweichen und damit der von Pascal propagierten strukturierten
Programmierung den Rücken zu kehren. In C, wo die Bedingung im Kopf der
For-Schleife optional ist, bedarf es dieser Verrenkung nicht. Man könnte
deswegen sogar fast behaupten, dass C das bessere Pascal ist :)

Das for in C ist sozusagen das Schweizer Taschenmesser für Schleifen.

: Bearbeitet durch Moderator
von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Tja, sowohl Pascal als auch C haben eine 'for'-Anweisung. Und die ist
> eigentlich dazu gedacht, für eine abgezählte Anzahl von Dingen dasselbe
> zu tun.

Tja, eine for-Anweisung einer Programmiersprache macht genau das, was 
die Sprachdefinition dazu definiert. Und auch wenn es für dich 
vielleicht komisch klingt, kann und wird das von Programmiersprache zu 
Programmiersprache anderes sein.

Oliver

von W.S. (Gast)


Lesenswert?

Yalu X. schrieb:
> Man kann in C auch ...

Genau DAS schrieb ich bereits. Aber das ist ne Aufblähung, wie ich 
ebenfalls bereits schrieb. Ich weiß das alles, aber ich beurteile das 
als zu aufgebläht.

W.S.

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Ich weiß das alles, aber ich beurteile das
> als zu aufgebläht.

Stört ja auch niemanden.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

W.S. schrieb:
> ich beurteile das als zu aufgebläht.

Ok, dann ist C halt aufgebläht, und aus Pascal ist die Luft raus :)

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