Hallo,
ich habe momentan große Probleme bei einer for-schleife, welche
rückwärts läuft.
1
for(uint8_tx=5;x<0;x--)
2
{
3
...
4
}
hier geht x nur bis 1 und dann wird die Schleife wieder verlassen.
1
for(uint8_tx=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?
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.
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.
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_tx=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!
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--)
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...
felix schrieb:> ich habe momentan große Probleme bei einer for-schleife>
1
>for(uint8_tx=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!
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.
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.
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.
(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.
(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?
(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.
(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
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.
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.
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--)
Man kann schon unsigned mit "signed" vergleichen, wenn man es richtig
macht.
1
for(unsignedk=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.
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.
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).
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
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. ;-)
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.
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.ä.
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.
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! ;)
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 Textkotz, die Zeit von Assembler ist schon lange vorbei.
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.
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 ....
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
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.
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(unsignedchari=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(unsignedchari=5;i--;)
2
g();
wird in jeder Optimierungsstufe > 0 das draus:
call g
call g
call g
call g
...
jmp g
(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?
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.
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.
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.
(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
intinrange(intx,intg1,intg2)
2
if(g1<g2)
3
returnx>=g1&&x<=g2;
4
returnx>=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.
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
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!
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.
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?
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 ....
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.
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.
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.
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. ;)
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!
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.
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.
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.
(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.
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