Forum: Mikrocontroller und Digitale Elektronik for-schleife rückwärts bis auf 0 laufen lassen probleme


von felix (Gast)


Lesenswert?

Hallo,
ich habe momentan große Probleme bei einer for-schleife, welche 
rückwärts läuft.
1
for(uint8_t x=5; x<0; x--)
2
{
3
...
4
}

hier geht x nur bis 1 und dann wird die Schleife wieder verlassen.
1
for(uint8_t x=5; x<=0; x--)
2
{
3
...
4
}
hier geht es zwar bis 0, fängt dann aber wieder bei 255 an. Also diese 
schleife wird nie verlassen.

Wie kann ich denn in einer for-schleife bis einschließlich 0 laufen?

von Franko P. (sgssn)


Lesenswert?

Hi
wieso x<0? du meinst x>0
und uint ist hier wohl schlecht.
Gerhard

: Bearbeitet durch User
von nicht"Gast" (Gast)


Lesenswert?

for(int x=5;x=>0;x--)

du hast die Bedingung falsch herum. Die Schleife wird so lange 
ausgeführt, wie die Bedingung wahr ist.

von Dirk F (Gast)


Lesenswert?

felix schrieb:
> for(uint8_t x=5; x<=0; x--)

for(uint8_t x=5; x>-1; x--)

von MaWin (Gast)


Lesenswert?

felix schrieb:
1
for(uint8_t x=6; x-- >0;)
2
{
3
   ...
4
}
wäre wohl besser.

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


Lesenswert?

felix schrieb:
> for(uint8_t x=5; x<0; x--)
> {
> ...
> }
> hier geht x nur bis 1 und dann wird die Schleife wieder verlassen.
Bist du ganz sicher?
Denn ein uin8_t kann niemals negativ, also kleiner 0 werden. Ergo wird 
diese Schleife eigentlich nie ausgeführt.

von (prx) A. K. (prx)


Lesenswert?

Dirk F schrieb:
> for(uint8_t x=5; x>-1; x--)
Ausprobiert? Das ist gewissermassen die Umkehrung zu
> for(uint8_t x=5; x<0; x--)

Eins wird ad infinitum ausgeführt, das andere nie.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

MaWin schrieb:
> felix schrieb:for(uint8_t x=6; x-- >0;)
> {
>    ...
> }
> wäre wohl besser.

Klar, noch mehr Obfuscation! Sinnloser Hacker-Müll!
Wenn, dann so!
1
for(int8_t x = 5; x >= 0; x--)
2
{
3
...
4
}

Der "Trick" liegt in der Verwendung einer VORZEICHENBEHAFTETEN Variable, 
also int8_t statt uint8_t. Denn die Schleife wird solange durchlaufen, 
wie die Bedingung wahr ist. Eine for() - Schleife kann man auch so 
sehen, als while(schleife)
1
for(Initialisierung; Laufbedingung; Modifikation)
2
3
// äquivalent zu
4
5
Initialisierung
6
while(Bedingung) {
7
// mach was
8
Modifikation;
9
}

D.h. aber auch, daß beim Abbruch die Laufvariable vorher noch einmal 
modifiziert wird und danach die Laufbedingung ungültig wird. Bei dieser 
letzten Modifikation darf aber kein Überlauf erfolgen! D.h. wenn ich 
eine Schleife von x bis runter auf 0 durchlaufen will, muss die Variable 
auch den Wert -1 annehmen können. Das können nur vorzeichenbehaftete 
Zahlen. Und bitte KEINE Hackertricks ala Vergleich mit 255 oder so! Das 
ist ganz schlechter Stil, mit dem man sich gern ins Knie schießt!
1
// So nicht! Hackermist!!!
2
for(int8_t x = 5; x !=255 ; x--)
3
{
4
...
5
}

Strukturierte Programmierung auf Mikrocontrollern

von (prx) A. K. (prx)


Lesenswert?

Falk B. schrieb:
> // So nicht! Hackermist!!!
> for(int8_t x = 5; x !=255 ; x--)

Das ist nicht nur unschön, sondern schlicht falsch.

So ist es zwar auch nicht schön, aber korrekt:
  for(uint8_t x = 5; x != UINT_MAX ; x--)

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


Lesenswert?

(prx) A. K. schrieb:
> UINT_MAX
Ist das nicht 65535?

von (prx) A. K. (prx)


Lesenswert?

Ja. UINT8_MAX

: Bearbeitet durch User
von Jens M. (schuchkleisser)


Lesenswert?

Bin ja nicht so der Held mit C in jeder Couleur, kleine Sachen mach ich 
in Assembler, und in C zähle ich vorwärts weil's menschenverständlicher 
ist, aber echt jetzt mal:
Jeder prickelige kleine Controller hat mehr Befehle zum Rückwärtszählen 
und Testen auf Null als andersrum, und in C kann man das nicht abbilden?
Da kann ich den C-Hater aber doch durchus verstehen...

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


Lesenswert?

felix schrieb:

> ich habe momentan große Probleme bei einer for-schleife
>
1
> for(uint8_t x=5; x<0; x--)
2
> ...
3
>

Anfängerfehler.

Eine uint-irgendwas_t Variable kann niemals kleiner 0 werden.
Das weiß der Compiler auch und warnt entsprechend.

Compilerwarnungen eingeschaltet lassen und lesen!

von Stefan F. (Gast)


Lesenswert?

MaWin schrieb:
> for(uint8_t x=6; x-- >0;)
> {
>    ...
> }
> wäre wohl besser.

Sorry Mawin, aber so programmiert man nur als Einzelkämpfer, wenn man 
verhindern will, dass andere den Quelltext lesen können.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> und in C kann man das nicht abbilden

Natürlich kann man. Und das wurde bereits genannt:
   for (uint8_t x = 5; x--; )

von Stefan F. (Gast)


Lesenswert?

Axel S. schrieb:
> Eine uint-irgendwas_t Variable kann niemals kleiner 0 werden.
> Das weiß der Compiler auch und warnt entsprechend.
>
> Compilerwarnungen eingeschaltet lassen und lesen!

Guter Tipp. Dann fällt einem auch auf, dass man gar nicht negativ werden 
wollte und denkt kurz nach, warum der Compiler das denn "denkt". Und 
schon hat man die Lösung.

Ich bin es gewohnt, dass die IDE solche Sachen schon beim Tippen 
bemängelt.

Qt-Creator macht das z.B., diese IDE kann man sehr gut als "externen 
Editor" mit Arduino benutzen.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Mit uint als do/while:
1
uint8_t i=5;
2
do {
3
  foo(i);
4
} while(x--);

von Random .. (thorstendb) Benutzerseite


Lesenswert?

MaWin schrieb:
1
 for(uint8_t x=6; x-->0;)
Ah, der Limes-Operator :-)

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Random .. schrieb:
> Mit uint als do/while:

In diesem speziellen Fall ja. Die for() Version ist allerdings auch dann 
geeignet, wenn es nicht
   for (uint8_t x = 5; ...)
heisst, sondern
   for (uint8_t x = n; ...)
und n auch 0 sein kann.

Es gab eine Zeit, in der die do{}while Lösung effizienter war, aber das 
ist viele Jahrzehnte her.

von Jens M. (schuchkleisser)


Lesenswert?

(prx) A. K. schrieb:
> Natürlich kann man. Und das wurde bereits genannt:
>    for (uint8_t x = 5; x--; )

Ich hoffte, das man kann, auch ohne eine signed variable zu benutzen, 
danke.
2 Dinge aber dennoch:
a) Wo bereits genannt? ;)
b) Du obfuskierst da auch was. Auf den ersten Blick sieht's aus als 
hättest du was vergessen. Den Test auch gleich für die Rechnung zu 
benutzen ist fies, so wie der Anfängerfehler "If a=5 then"...
Ansonsten wäre mir auc nur Do/While eingefallen.

von Jens M. (schuchkleisser)


Lesenswert?

(prx) A. K. schrieb:
> Es gab eine Zeit, in der die do{}while Lösung effizienter war, aber das
> ist viele Jahrzehnte her.

Aus dem Stegreif hätte ich gesagt, das do/while näher am Maschinencode 
ist und sich einfacher umsetzen ließe. Stichwort DEC/BNE, DECFSZ und wie 
sie alle heißen.
Leider weiß ich, das die meisten Compiler fürchterlich großen Code 
erzeugen, für eigentlich 3-10 Maschinenbefehle werden Unmengen an 
Pseudostack und Calls verbraten. Von daher könntest du Recht haben...

Worauf beziehst du dich? Kürzer? Schneller? Woher hast du die Info?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Random .. schrieb:
>> Mit uint als do/while:
>    for (uint8_t x = n; ...)
> und n auch 0 sein kann.

Hier ist n=0 ein valider Parameter, weswegen ich auch die do/while 
vorgeschlagen habe. Oft sinnvoll bei eigenen Stringoperationen, damit 
man aus do{}while(*p++); die \0 mitbekommt (wohingegen man bei 
do{}while(*++p); den String als "geprüft" vorraussetzt und die \0 nicht 
haben will, und das einfacher auch als while(*p++){} schreiben kann :-) 
).
Natürlich muss man sich vorher Gedanken machen, was genau man braucht.

von Mathias (Gast)


Lesenswert?

(prx) A. K. schrieb:
> for (uint8_t x = 5; x--; )

Weil ich das nicht so gerne lese, würde ich das expliziter schreiben:
for (uint8_t x = 5; x--==0; )
Die Schleife fängt aber unintuitiver weise schon bei 4 an... Daher hier 
mein Vorschlag:

for (uint8_t x = 5; x != (uint8_t) -1; x--)
Smiley mit Zahnlücke

von Volkker (Gast)


Lesenswert?

warum nicht int8_t ?

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> a) Wo bereits genannt? ;)

Bei MaWin, dem Prinzip nach. Nur hatte er ein redundantes >0 drin und 
sich verzählt. Ich ziehe die kompaktere Darstellung vor.

> b) Du obfuskierst da auch was. Auf den ersten Blick sieht's aus als
> hättest du was vergessen. Den Test auch gleich für die Rechnung zu
> benutzen ist fies

Das Ergebnis von --/++ direkt zu nutzen ist gängige Praxis. Bei Pointern 
macht das in Form von z.B. while(*p++) jeder. Weshalb also nicht hier? 
Eine Streitfrage könnte sein, ob man explizit x-- != 0 schreiben sollte, 
oder es bei x-- belässt.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Mathias schrieb:
> for (uint8_t x = 5; x != (uint8_t) -1; x--)
> Smiley mit Zahnlücke

So weit ich weiss ist Einerkomplementdarstellung immer noch in C 
Implementierungen zulässig. Sign/Magnitude vmtl auch.

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


Lesenswert?

So viele Ideen (und die Hälfte falsch) für eine Schleife von 5...0 UND 
der Forderung eines unsigned Schleifenzählers.

Ich glaube, sicherer (lesbarer, verständlicher) wäre es, einen int 
Schleifenzähler zu nehmen und in der ersten Zeile auf eine uint 
zuzuweisen.


Ich würde für mich

(uint8 x=5; x<=5; x--)

nehmen. Und wenn der Typ nicht in der Zeile ersichtlich ist, gerne && 
x>=0 dazu.

Wobei ... ich bin kein Freund von Einzeiler in Funktionen, wirklich 
nicht. Aber eine Funktion inrange(x, grenze1, grenze2) nutze ich 
tausendfach (wobei egal ist, welche Grenze größer ist)

Also hier:

for (uint8 x=5; inrange (x,0,5); x--)

von Luther B. (luther-blissett)


Lesenswert?

Man kann schon unsigned mit "signed" vergleichen, wenn man es richtig 
macht.
1
for (unsigned k=5;k!=-1u;k--)

Begründung findet sich im C Standard 
(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf), Kapitel 
6.2.5 Abschnitt 9:

> A computation involving unsigned operands can never overflow,
> because a result that cannot be represented by the resulting unsigned integer 
type is
> reduced modulo the number that is one greater than the largest value that can be
> represented by the resulting type."

Für unsigned int wird also (a-b) mod n gerechnet, mit n=UINT_MAX+1 (z.B. 
2^32)

-1u ist daher wohldefiniert, enspricht dem Wert 0u-1u und stellt die 
Zahl da, die man erhält, wenn man 0u um den Betrag 1 verringert.

von (prx) A. K. (prx)


Lesenswert?

A. S. schrieb:
> Aber eine Funktion inrange(x, grenze1, grenze2) nutze ich
> tausendfach (wobei egal ist, welche Grenze größer ist)

Du verlagerst das Problem nur in diese Funktion. Das kann sinnvoll sein, 
eben weil in diesem Zusammenhang zu viel Mist rumschwirrt. Die Kernfrage 
bleibt aber erhalten, irgendwer muss diese Funktion wasserdicht 
implementieren, ohne dabei zu viel Aufwand im Code zu erzeugen.

von (prx) A. K. (prx)


Lesenswert?

Luther B. schrieb:
> wenn man es richtig macht.

Ja, wenn man es gleich richtig macht, geht vieles wie von selbst. ;-)

Allerdings wirds dann subtil, denn bei
  for (ushort_t ...)
kann das Verhalten solcher Spielchen davon abhängen, ob
  sizeof(short) < sizeof(int).

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Jens M. schrieb:
> Jeder prickelige kleine Controller hat mehr Befehle zum Rückwärtszählen
> und Testen auf Null als andersrum, und in C kann man das nicht abbilden?
> Da kann ich den C-Hater aber doch durchus verstehen...

Du hast das Problem gar nicht verstanden. Da kann C nichts dafür.

Oliver

von Falk B. (falk)


Lesenswert?

Hackertrick 2.0 mit Unterlauf
1
for(uint8_t x=5; x <= 5; x--) {
2
// mach was
3
}

von Ben S. (bensch123)


Lesenswert?

Also ich persönlich finde das die sauberste Lösung.
1
for(uint8_t i = 10; i-- > 0;){
2
}

Oder:
1
for(uint8_t i = 10; i > 0; i--){
2
  uint8_t j = i - 1;
3
  //...
4
}

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Ben S. schrieb:
> for(uint8_t i = 10; i-- > 0;)

Wobei der Unterschied zu
  for(uint8_t i = 10; i--;)
religiöse Dimensionen annehmen kann. Es soll Leute gegeben, die
  bool flag; if (flag == TRUE)
schreiben. ;-)

von Ben S. (bensch123)


Lesenswert?

(prx) A. K. schrieb:
> for(uint8_t i = 10; i--;)

Hier hingegen wirds schwer lesbar. Da muss man erstmal nachdenken ..

von (prx) A. K. (prx)


Lesenswert?

Ben S. schrieb:
> for(uint8_t i = 10; i > 0; i--){
>   uint8_t j = i - 1;

Es gibt in C eine Reihe gängiger Ausdrücke, die man je nach Laune auch 
komplizierter ausdrücken kann als nötig. Je komplizierter, desto 
aufwändiger ist die Erkennung davon, was da eigentlich geschieht. 
Weshalb ich es für sinnvoller halte, die sprachtypischen Muster zu 
erlernen.

Ben S. schrieb:
> Da muss man erstmal nachdenken

Jede Sprache muss man erst einmal lernen. Auch C.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Was ist nur aus der guten, alten Zeit geworden, als man einfach genau 
DAS hingeschrieben hat was man wollte, ohne dreimal um die Ecke zu 
denken?
1
For i=5 downto 0 step -1
2
Next

von felix (Gast)


Lesenswert?

Vielen Dank euch allen.

Das hier
1
for(int8_t x = 5; x >= 0; x--)
2
{
3
...
4
}

hat mir weitergeholfen.
Euer restliches Geschwurbel leider überhaupt nicht. Es ging mir darum, 
wie die Schleife bis 0 laufen kann und nicht um irgendwelche 
Grundsatzdiskussionen, Programmiersprachen o.ä.

von Jens M. (schuchkleisser)


Lesenswert?

Oliver S. schrieb:
> Du hast das Problem gar nicht verstanden.

Das Problem ist eine Schleife von 5 bis 0 (also 6 Durchläufe), die in C 
lesbar und lauffähig ist.
Oder?

Oliver S. schrieb:
> Da kann C nichts dafür.

C soll einfach (und damit mit weniger Fehlern) zu schreiben und zu lesen 
sein.
In Assembler geht so eine Schleife in wenigen Befehlen, z.B. beim PIC:
1
movlw 5       ; Zählerwert laden
2
movwf cnt     ; in Zählervariable speichern
3
loopstart:    ;  Schleifenanfang
4
...           ; Schleife
5
...
6
...
7
decf cnt      ; Zähler verringern
8
bnb loopstart ; Kein Unterlauf? Dann weiter mit "Schleife"
9
...           ; sonst fertig, weiter im Text
bnb ist ein Pseudocodemakro für einen Bittest auf Borrow, aufgelöst 
sinds zwei Befehle, einmal btfs (bittest) und einmal goto.
Also ganze 5 Befehle, die innerhalb des Wertebereichs 0-255 die Schleife 
1-256x laufen lassen.

Bitte in C. Ich lern gern dazu. Das Ding von prx oben finde ich elegant, 
wenn auch für mich noch schwer lesbar, weil eben ein Teil des For fehlt.
Und ich bin sicher, das ein C-Compiler (egal welcher auf egal welcher 
Achitektur) nicht diesen oder einen vergleichbaren Code produziert, 
sondern was deutlich längeres.
Die wenigen die ich bis jetzt gesehen habe jedenfalls tun's.

von Jens M. (schuchkleisser)


Lesenswert?

Falk B. schrieb:
> For i=5 downto 0 step -1
> Next

Impliziert "downto" nicht "Step -1"?
Entweder "to" mit "Step -1", oder "downto" ohne Step, zumindest solange 
step = 1|-1.
Und: Iiiih, BASIC! ;)

: Bearbeitet durch User
von Ben S. (bensch123)


Lesenswert?

Jens M. schrieb:
> Die wenigen die ich bis jetzt gesehen habe jedenfalls tun's.

Vermutlich hast du noch nicht viele gesehen.

Jens M. schrieb:
> Bitte in C. Ich lern gern dazu. Das Ding von prx oben finde ich elegant,
> wenn auch für mich noch schwer lesbar, weil eben ein Teil des For fehlt.
> Und ich bin sicher, das ein C-Compiler (egal welcher auf egal welcher
> Achitektur) nicht diesen oder einen vergleichbaren Code produziert,
> sondern was deutlich längeres.

Für Assembler Fetischisten ist das natürlich ein Argument. Als 
Hochsprachenentwickler weiß ich jedoch, dass das in der Regel völlig 
wumpe ist und erfreue mich daran in C/C++ 100mal so 
schnell/fehlerfreier/plattformunabhängiger/übersichtlicher zu sein wie 
du in Assembler, denn:

Jens M. schrieb:
> movlw 5       ; Zählerwert laden
> movwf cnt     ; in Zählervariable speichern
> loopstart:    ;  Schleifenanfang
> ...           ; Schleife
> ...
> ...
> decf cnt      ; Zähler verringern
> bnb loopstart ; Kein Unterlauf? Dann weiter mit "Schleife"
> ...           ; sonst fertig, weiter im Text

kotz, die Zeit von Assembler ist schon lange vorbei.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Und ich bin sicher, das ein C-Compiler (egal welcher auf egal welcher
> Achitektur) nicht diesen oder einen vergleichbaren Code produziert,
> sondern was deutlich längeres.

Bis in die 80er haben C Compiler wirklich ziemlich 1:1 das produziert, 
was im Quellcode stand. Allein schon deshalb, weil der Compiler oft in 
64kB passen musste und für Optimierung dann wenig Platz war.

Ich will nicht ausschliessen, dass einfacher gestrickte Compiler für 
kleine Mikrocontroller es immer noch so halten. Gute Compiler sind indes 
nicht selten pfiffiger als der Programmierer.

von Danke (Gast)


Lesenswert?

felix schrieb:
> Euer restliches Geschwurbel leider überhaupt nicht.

Das kann ich gut verstehen. Die Korinthenkackerei um nur jede
denkbare und syntaktisch richtige Variation der Ausformulierung
der Schleife nervt mich. Was die Leute alles nicht zu tun haben
um sich um solche Dinge kümmern zu müssen ....

von Oliver S. (oliverso)


Lesenswert?

Jens M. schrieb:
> Das Problem ist eine Schleife von 5 bis 0 (also 6 Durchläufe), die in C
> lesbar und lauffähig ist.
> Oder?

Nein. Das Problem war eine Schleife, die mit einer 
unsigned-Schleifenvariable von 5 bis 0 zählt. Das ist mit einer 
for-Schliefe in C mühsam. Mit einer do...while Schleife, die deinem 
Assembler-Ansatz entspricht, wäre es kein Problem gewesen.

Oliver

von felix (Gast)


Lesenswert?

Das Problem und auch die Frage war im ersten Post genau beschrieben.

von Danke (Gast)


Lesenswert?

felix schrieb:
> Das Problem und auch die Frage war im ersten Post genau beschrieben.

Das wollen die Korinthenkacker und Schwurbler aber gar nicht
hören. Die wollen lieber weitermachen wie es ihnen gefällt.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Die wenigen die ich bis jetzt gesehen habe jedenfalls tun's.

8-Bit PICs und die C-Sprache sind nicht wirklich füreinander geschaffen.

Jens M. schrieb:
> Die wenigen die ich bis jetzt gesehen habe jedenfalls tun's.
1
for (unsigned char i = n; i--; )
2
          g();
führt auf gcc/amd64 zu
        call    g
        subb    $1, %bl
        jne     .L7

Preisfrage: Weshalb wird hier subtrahiert, nicht dekrementiert?

Bei
1
for (unsigned char i = 5; i--; )
2
          g();
wird in jeder Optimierungsstufe > 0 das draus:
        call    g
        call    g
        call    g
        call    g
        ...
        jmp     g

: Bearbeitet durch User
von Danke (Gast)


Lesenswert?

(prx) A. K. schrieb:
> 8-Bit PICs und die C-Sprache sind nicht wirklich füreinander geschaffen.

Hallo Schwurbel-prx, was hat das mit dem Thema des TO zu tun?

Willst vielleicht noch einen Vortrag über Compiler-Architekturen
halten?

von (prx) A. K. (prx)


Lesenswert?

Danke schrieb:
> Hallo Schwurbel-prx, was hat das mit dem Thema des TO zu tun?

Es gibt verschiedene Arten, sich so einem Problem zu widmen. Man kann 
sich eine alternative Lösung geben lassen, oder man kann zu verstehen 
versuchen, woran man gescheitert ist.

Forendiskussionen sind zudem nicht im Besitz des Erstposters, sind 
mithin nicht exakt auf dessen ursprüngliche Fragestellung beschränkt, 
sondern es werden auch Antworten auf Antworten anderer gegeben. Das war 
hier der Fall.

: Bearbeitet durch User
von Freitag (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Es gibt verschiedene Arten, sich so einem Problem zu widmen.

Mit Kanonen auf Spatzen zu schießen, zum Beispiel.

von (prx) A. K. (prx)


Lesenswert?

Freitag schrieb:
> Mit Kanonen auf Spatzen zu schießen, zum Beispiel.

Denken lernen halt ich für sinnvoller als dumm bleiben. Aber das darfst 
du für dich gerne anders entscheiden.

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


Lesenswert?

felix schrieb:
> Es ging mir darum, wie die Schleife bis 0 laufen kann und nicht um
> irgendwelche Grundsatzdiskussionen
In diesen Diskussionen steckt aber lustigerweise die Information für das 
grundlegende Verständnis der Problematik.

> Es ging mir darum, wie die Schleife bis 0 laufen kann
Oder ehrlich: es ging dir darum, möglichst schnell eine Lösung für dein 
Problem zu bekommen.

felix schrieb:
> Das Problem und auch die Frage war im ersten Post genau beschrieben.
Mit ein wenig "Nachdenken" und "Ausprobieren" (nennen wir es einfach 
kurz "Lernen") hättest du da selber draufkommen können.

Aber du kannst ja das nächste Mal, wenn du wieder (ich zitiere dich) 
"momentan große Probleme" hast, genauso momentan zur "Publikumsfrage" 
greifen und die "Schwarmintelligenz" nutzen, statt das Ding zwischen den 
Ohren zum Einsatz zu bringen.

Und, Freitag-felix: bitte nur 1 Nutzername pro Thread. So steht es in 
den simplen Nutzungsbedingungen.

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


Lesenswert?

(prx) A. K. schrieb:
> A. S. schrieb:
>> Aber eine Funktion inrange(x, grenze1, grenze2) nutze ich
>> tausendfach (wobei egal ist, welche Grenze größer ist)
>
> Du verlagerst das Problem nur in diese Funktion. Das kann sinnvoll sein,
> eben weil in diesem Zusammenhang zu viel Mist rumschwirrt. Die Kernfrage
> bleibt aber erhalten, irgendwer muss diese Funktion wasserdicht
> implementieren, ohne dabei zu viel Aufwand im Code zu erzeugen.

Mir ist nicht ganz klar, was Du meinst: Die Funktion inrange testet nur, 
ob x innerhalb von (einschließlich) grenze1 und grenze2 liegt. So in der 
Art:
1
int inrange(int x, int g1, int g2)
2
if(g1 < g2) 
3
   return x>=g1 && x<= g2;
4
return    x>=g2 && x<= g1;
Ja, gerne auch bool, und ja, für unsigned oder Long geht das so nicht in 
C. Wenigstens nicht einfach. Aber für alles was <= int ist.

Und wenn diese Funktion geinlined wird, zerfällt sie (da hier die 
Grenzen ja fix sind) zur minimalen Abfrage OHNE eine Warnung zu 
generieren, wie es bei
1
for(x=5; x<=5 && x>=0; x--)
der Fall wäre (wegen x>=0) und trotzdem korrekt wen jemand nachträglich 
(unbedarft) int8_t aus x macht.

von Stefan F. (Gast)


Lesenswert?

Wie war das noch: Mit C kann man sich optimal ins Knie schießen

von Jens M. (schuchkleisser)


Lesenswert?

Ben S. schrieb:
> 100mal so
> schnell

Niemals. Ein effizienter ASM-Schreiber ist nicht wesentlich langsamer 
als ein C-Schreiber. Dafür tut's evtl. ein kleinerer Chip, bei 
Massenprodukten evtl. ein Preisvorteil.
Einigen wir uns auf "Doppelt so schnell" in C. Geschenkt.

Ben S. schrieb:
> fehlerfreier

Wie man oben sieht, nicht unbedingt. Man muss beide Sprachen natürlich 
beherrschen. Ist also kein Punkt.

Ben S. schrieb:
> plattformunabhängiger

Ernsthaft? Wann hast du jemals einen Code in eine völlig andere 
Plattform transferiert? Speziell bei Controllern muss man irgendwann an 
die Hardware, und wenn die eine UART anders funktioniert wie die 
gewohnte ist der Code schrott.
Oder du kaufst noch mehr MHz und packst noch eine HAL dazwischen. 
Jesses.
Zählt also auch nicht.

Ben S. schrieb:
> übersichtlicher

Hahaha. Wenn das so übersichtlich ist, warum ist dann alles voller 
Fehler hier im Thread? Die meisten davon basieren auf 
Verständnisproblemen, weil eben nicht jedem klar ist, wie das mit dem 
For geht.

Ben S. schrieb:
> kotz, die Zeit von Assembler ist schon lange vorbei.

Also hast du noch nie nachgesehen und ersetzt Effizienz mit MHz.
Und du kannst es nicht besser.

Ben S. schrieb:
> Vermutlich hast du noch nicht viele gesehen.

lies. "wenige". verstehe.
Es waren einige für Atmels, PIC, MIPS, LPC. Alle machen aus einem 
"Blink" etliche -zig bis -hundert Bytes.
Knaller: 8-poliges NXP-Testset bekommen, zum Einstieg in die LPC-Welt. 
Yay.
Testcode bringt eine LED zum blinken, Testbrett blinkt.
Schreibe eine zweite LED dazu, die invers blinkt. Sollte "Pin != Bool" 
sein, weil die erste LED mit "Pin = Bool" blinkt.
Oha, kein Speicher mehr. Der f*ing Chip hat etliche tausend 
Speicherzellen für das Programm, aber die Pflicht-Library, die die 
Hardware initialisiert und den unnötigen SysTick erzeugt frißt 99% des 
Platzes.
War wohl zu einfach, den Compiler den Rest rausoptimieren zu lassen.
Geradeaus in die Tonne damit, Hausverbot für den Hersteller.

(prx) A. K. schrieb:
> Gute Compiler sind indes
> nicht selten pfiffiger als der Programmierer.

Arduino basiert auf dem GCC. Ist der nach dieser Definition "gut"?

Oliver S. schrieb:
> Mit einer do...while Schleife, die deinem
> Assembler-Ansatz entspricht, wäre es kein Problem gewesen.

hurr. Ich hab das richtig erkannt und doch falsch? grmpf

(prx) A. K. schrieb:
> 8-Bit PICs und die C-Sprache sind nicht wirklich füreinander geschaffen.

Dafür steht in vielen Datenblättern aber "speciali(s)ed instruction set 
for C" ;) (Umgehung es Spamfilters für Herrenmedikamente)
Gilt auch für Atmels.
Auf Intel war ich nie unterwegs...

(prx) A. K. schrieb:
>         call    g
>         call    g
>         call    g
>         call    g
>         jmp     g
So einfach... :D

von Oliver S. (oliverso)


Lesenswert?

Jens M. schrieb:
> Bitte in C. Ich lern gern dazu.

Bitte sehr:
https://godbolt.org/z/xeM35s

Oliver

von Ben S. (bensch123)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wie war das noch: Mit C kann man sich optimal ins Knie schießen

Mit Assembler noch viel mehr. Warum kapiert das keiner?

von Ben S. (bensch123)


Lesenswert?

Jens M. schrieb:
> Einigen wir uns auf "Doppelt so schnell" in C. Geschenkt.

Träum weiter.

Jens M. schrieb:
> Hahaha. Wenn das so übersichtlich ist, warum ist dann alles voller
> Fehler hier im Thread?

Weil die Leute das schnell hinschei**en.

Jens M. schrieb:
> Niemals. Ein effizienter ASM-Schreiber ist nicht wesentlich langsamer
> als ein C-Schreiber.

Logisch. Warum gibts überhaupt Hochsprachen? Weg damit!

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
>> 8-Bit PICs und die C-Sprache sind nicht wirklich füreinander geschaffen.
>
> Dafür steht in vielen Datenblättern aber "speciali(s)ed instruction set
> for C" ;)

Bei den 8-Bit PICs mit 16-Bit Befehlsbreite wurde in der zweiten 
Revision der Architektur der Murks von früher repariert. Schön ists 
immer noch nicht, aber wesentlich besser.

von Jens M. (schuchkleisser)


Lesenswert?

Oliver S. schrieb:
> Bitte sehr:
> https://godbolt.org/z/xeM35s

Danke.
Das ist aber eine do-while. Wie's in for geht, weiß ich dank prx nun 
auch.

Ben S. schrieb:
> Mit Assembler noch viel mehr. Warum kapiert das keiner?

Wenn man's kann, nicht. Man muss sein Werkzeug beherrschen, egal ob 
Basic, Arduino, C(++/#) oder Asm.
Mein Vorteil für Asm: Ich weiß, welche Variablen wo liegen und wie viel 
RAM über ist, das können viele Compiler aus mir unerfindlichen Gründen 
nicht.
Und so ein Quatsch wie "println("Text");" wo der Text bei Start ins RAM 
kopiert wird und da bis zum St. Nimmerleinstag wartet um mal geUARTet zu 
werden, mannomann. Auf so einen Schrott käme man als Asm-Programmierer 
gar nicht, wozu einen festen Wert ins RAM kopieren?

von Ben S. (bensch123)


Lesenswert?

Jens M. schrieb:
> Mein Vorteil für Asm: Ich weiß, welche Variablen wo liegen und wie viel
> RAM über ist, das können viele Compiler aus mir unerfindlichen Gründen
> nicht.

Und? Ist das wichtig? Vielleicht vor 20 Jahren. Ich kriege heute für <1€ 
8bit µC mit einigen kByte Ram. Bei Neuentwicklungen tu ich mir das 
definitiv nicht mehr an.

Ist nicht so, dass ich kein Assembler kann, aber ....

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Und so ein Quatsch wie "println("Text");" wo der Text bei Start ins RAM
> kopiert wird und da bis zum St. Nimmerleinstag wartet um mal geUARTet zu
> werden, mannomann. Auf so einen Schrott käme man als Asm-Programmierer
> gar nicht, wozu einen festen Wert ins RAM kopieren?

Das kommt dabei raus, wenn die Prozessorarchitektur nicht wirklich mit C 
im Auge geschaffen wurde. Oder weil aufgrund der Ausrichtung als kleinem 
Mikrocontroller Kompromisse nötig waren, die in Konflikt mit effizientem 
C stehen. So wurde C bei den AVRs zwar berücksichtigt, aber die aus der 
Adressraumtrennung resultierenden Probleme blieben. Und genau um die 
geht es bei Strings.

: Bearbeitet durch User
von Jens M. (schuchkleisser)


Lesenswert?

Ben S. schrieb:
> Logisch. Warum gibts überhaupt Hochsprachen? Weg damit!

Weil man damit leichter Libraries von anderen Leuten einbinden kann.
Ich muss zugeben, bei Arduino zum Debuggen mal eben ein "println" 
hinzurotzen ist weitaus einfacher als sich sowas mal eben in Asm 
zusammenzustückeln... ;)

Hochsprachen verschieben die Zeit vom Programmersteller zum 
Programmausführer.
Man kann schneller was schreiben, ohne sich bewusst zu sein, was die 
eine Zeile bedeutet, und dafür muss der Einkauf dann eben mehr MHz 
besorgen.
Und Wissen wird durch Stackoverflow ersetzt.
Daher werden die Programme auch immer schneller langsamer als die 
Hardware schneller wird.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Ben S. schrieb:
>> plattformunabhängiger
>
> Ernsthaft? Wann hast du jemals einen Code in eine völlig andere
> Plattform transferiert? Speziell bei Controllern muss man irgendwann an
> die Hardware, und wenn die eine UART anders funktioniert wie die
> gewohnte ist der Code schrott.

Wenn man eine komplexe Kommunikation über UART abwickelt, beispielsweise 
über einen RS485 Bus, dann ist der grösste Teil des Codes invariant. 
Weshalb man das gleiche Software-Modul sowohl für AVR (Nodes) als auch 
für ARM (Zentrale) verwenden kann, nur das direkte Interface zur UART 
muss man anpassen. Mit ordentlicher Organisation des Codes geht das 
relativ einfach.

: Bearbeitet durch User
von Jens M. (schuchkleisser)


Lesenswert?

Und, wie oft macht man sowas? Ist ne ernsthafte Frage, ich kann mir das 
nicht vorstellen.
Benutzt man tatsächlich lieber 32 Controller aus 32 Familien mit 32 
Compilern und Spezialitäten, anstatt bei einer Familie zu bleiben und 
die richtig von 8pin bis 144pin zu kennen?
Ich mein, bei AVR, PIC und auch STM32 ist die Bandbreite so groß, da 
findet sich sicher was. Und wenn man wechseln muss, weil es den xxx 
nicht in AVR gibt, sind eh alle Codebasen Müll, weil uralt und auf 8 
statt 32 bit ausgerichtet.
Also schreibt man besser neu.

Oder nicht?

Edit: Du hast editiert.
(prx) A. K. schrieb:
> Mit ordentlicher Organisation des Codes geht das
> relativ einfach.

Also muss man den Code vorher so schreiben, das er auf allen Plattformen 
schlecht funktioniert, anstatt auf einer super und auf anderen gar 
nicht.
Ich wette, das ist bei 99% des existierenden C nicht gemacht worden. ;)

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Jens M. schrieb:
> Und, wie oft macht man sowas? Ist ne ernsthafte Frage, ich kann mir das
> nicht vorstellen.

Wie so viele Dinge in dieser Welt.

> Benutzt man tatsächlich lieber 32 Controller aus 32 Familien mit 32
> Compilern und Spezialitäten, anstatt bei einer Familie zu bleiben und
> die richtig von 8pin bis 144pin zu kennen?

Die Horizont ist doch eher begrenzt. Schon mal drüber nachgedacht, daß 
andere Leute was entwickeln was dann von tausenden Leuten auf 
verschiedensten Plattformen genutzt wird?

> Ich mein, bei AVR, PIC und auch STM32 ist die Bandbreite so groß, da
> findet sich sicher was. Und wenn man wechseln muss, weil es den xxx
> nicht in AVR gibt, sind eh alle Codebasen Müll, weil uralt und auf 8
> statt 32 bit ausgerichtet.
> Also schreibt man besser neu.

Käskopp.

>
> Oder nicht?

Nicht!

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Und, wie oft macht man sowas?

Da ich nicht professionell Mikrocontroller programmiere, will ich nicht 
persönlich darüber urteilen. Verwendet habe ich schon etliche, teils aus 
Neugierde.

Portierungen generell habe ich im Laufe der Jahrzehnte schon etliche 
durch. Ob verschiedene Hardware mit verschiedenen Wortbreiten, 
verschiedene Betriebssysteme oder verschiedene Netzwerktypen. Da hilft 
es, den Code so zu organisieren, dass die plattformabhängigen Teile von 
den unabhängigen Teilen getrennt sind.

So gibt es durchaus Gründe, weshalb Linux auf sehr vielen Architekturen 
läuft. Das ist zwar nicht die Arduino-Ebene, aber das Grundprinzip, den 
Code ordentlich zu strukturieren, ist ähnlich.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Also muss man den Code vorher so schreiben, das er auf allen Plattformen
> schlecht funktioniert, anstatt auf einer super und auf anderen gar
> nicht.

Wie so oft hilft, wenn man weiss, was man tut.

Und nicht immer muss beste Laufzeit-Performance im Vordergrund stehen. 
Da kann es schon sein, dass die von mir gewählte Verarbeitung von 
CAN-Adressen auf einem ARM effizienter funktioniert als auf einem AVR. 
Passte trotzdem rein, dafür ist es aber für beide der gleiche API 
oberhalb der CAN-Hardware.

Oft spielt die Performance des Programmierers die grössere Rolle. Wie 
schnell hat man eine Lösung (nicht: wie schnell ist die Lösung) und wie 
wartbar ist der Code.

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


Lesenswert?

Jens M. schrieb:
> Und, wie oft macht man sowas? Ist ne ernsthafte Frage, ich kann
> mir das nicht vorstellen.
> Benutzt man tatsächlich lieber 32 Controller aus 32 Familien mit 32
> Compilern und Spezialitäten, anstatt bei einer Familie zu bleiben und
> die richtig von 8pin bis 144pin zu kennen?

Lieber eine. Aber das hast Du nicht in der Hand. Wenn es X nur woanders 
gibt, dann hast Du die zweite Familie. Wenn Du Pic sagst, hast Du eh 
schon schnell 2 oder 3 gänzlich unterschiedliche Familien.
Und wenn dann ein Fremdprojekt dazukommt, hast Du einen Strauß.

> Und wenn man wechseln muss, weil es den xxx
> nicht in AVR gibt, sind eh alle Codebasen Müll, weil uralt und auf 8
> statt 32 bit ausgerichtet.
> Also schreibt man besser neu.
>
Nein. Bei 10 Zeilen am Tag ist es nicht besser, 1000 Zeilen neu zu 
schreiben.

> Also muss man den Code vorher so schreiben, das er auf allen Plattformen
> schlecht funktioniert, anstatt auf einer super und auf anderen gar
> nicht.

Nein. Schreib ihn einfach in C99 oder Ansi und gut ist. Und wenn Du ihn 
portieren musst mit gleicher Endianes und gleicher intbreite, dann sind 
99% fertig, wenn Du die Compiler-Optionen und pragmas angepasst hast. 
Und die 1% HAL brauchen nur einen Bruchteil, egal wie schlecht Du 
gekapselt hast. Und jetzt kapselst Du besser.

Und wenn du anderes Endian hast, strikteres alignment, 32 statt 16 Bit 
int, dann kannst Du immer noch entscheiden, ob Du neu machst, 
transferiert oder plattformunabhängig wirst.

Es ist gerade nicht sinnvoll, als Anfänger konkrete Aufgaben für alle 
Plattformen kompatibel zu schreiben. A testet das keiner (funktioniert 
also nicht), B wird jede printf-Anweisung, ja jeder Vergleich komplex 
und unleserlich.

Und ja, eine Plattform kommt immer dazu: der PC für Entwicklung und 
Test. Zumindest bei little Endian. Eine Checksumme oder ein fifo sollte 
immer auch auf dem PC laufen.

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


Lesenswert?

(prx) A. K. schrieb:
> Forendiskussionen sind zudem nicht im Besitz des Erstposters, sind
> mithin nicht exakt auf dessen ursprüngliche Fragestellung beschränkt,
> sondern es werden auch Antworten auf Antworten anderer gegeben

Kurz gesagt: ein Forum ist keine Beratungsstelle.

Wer Hilfe möchte ohne Gegenfragen oder Belehrungen oder die Möglichkeit 
eines Abdriftens vom Thema, der soll sich bezahlte Hilfe suchen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Freitag schrieb:
> (prx) A. K. schrieb:
>> Es gibt verschiedene Arten, sich so einem Problem zu widmen.
>
> Mit Kanonen auf Spatzen zu schießen, zum Beispiel.

Bitte bei einem Nick pro Thread bleiben.

prx hat übrigens Recht: Was bringt es Dir, mit dem alleinigen Tipp 
int8_t statt uint8_t zufrieden zu sein? Es löst zwar Dein aktuelles 
Problem, aber beim nächsten Mal schlägst Du mit einem ähnlichen Problem 
dann wieder hier auf. Zwischen Verstehen und purem Anwenden gibts halt 
einen himmelweiten Unterschied.

Außerdem geht es in diesem Forum auch um Diskussionen um das eröffnete 
Thema und nicht nur um die alleinige Hilfestellung des TOs. Dafür wäre 
stackoverflow wesentlich besser geeignet.

"Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre 
einen Mann zu fischen und du ernährst ihn für sein Leben."

Konfuzius

: Bearbeitet durch Moderator
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.