Guten Abend.
Ich interessiere mich für die Gründe, aus denen manche Programmierer für
Architekturen, die vom Small Device C Compiler (SDCC) unterstützt
werden, nichtfreie Compiler (Keil, IAR, Cosmic, Raisonance, etc)
einsetzen. Es wäre schön, wenn die Antworten neben den Gründen auch die
jeweiligen Architekturen nennen würden.
Lang ist's her, vermute eine 2.x.0-Version:
PIC: Libraries waren nicht kompatibel, müssten aufwändig angepasst
werden, um mit dem SDCC zusammenzuspielen. (z.B. das USB-Framework für
16F4550 &co)
Inzwischen sind die PIC-Targets im SDCC unmaintained, oder?
Εrnst B. schrieb:> Inzwischen sind die PIC-Targets im SDCC unmaintained, oder?
Ja. Immerhin sind die von den PIC-Ports verwendeten gputils nun
anscheinend wieder maintained, so dass ein zukünftiger Maintainer der
PIC-Ports in SDCC eine Sorge weniger hätte.
Zu den Gründen könnte gehören, daß mehr als nur ein Compiler benötigt
wird, sondern auch eine Debugunterstützung. PICs beispielsweise kann man
mit dem Microchip Studio beglücken, und da funktionieren PicKit, Mplab
Snap etc. als Programmier- und Debuginterfaces.
Und wenn so eine Entwicklungsumgebung eines Herstellers eh' schon
verwendet wird, und nur eine neue Architektur hinzukommt, muss der
Nutzer sich nicht umstellen. Microchip Studio (um beim Beispiel zu
bleiben) kann eben als Nachfolger des Atmel Studio nicht nur AVRs,
sondern auch PICs und Atmel-ARM (SAMDirgendwas) programmieren.
Für AVRs steckt da ein avrgcc drin, aber es gibt auch den
microchipeigenen XC8 als Compiler (der ohne zusätzliche Lizenz nur
eingeschränkt, d.h. ohne Optimierung verwendbar ist).
In manchen Entwicklungsszenarien ist eine Zertifizierung nach
irgendwelchen Richtlinien erforderlich (MISRA, kann wohl von IAR geboten
werden).
Es gibt also eine ganze Latte von Gründen-
DerEgon schrieb:> Zu den Gründen könnte gehören, daß mehr als nur ein Compiler benötigt> wird, sondern auch eine Debugunterstützung. PICs beispielsweise kann man> mit dem Microchip Studio beglücken, und da funktionieren PicKit, Mplab> Snap etc. als Programmier- und Debuginterfaces.
Genau. Und das nicht nur für PIC16, sondern auch für PIC18, PIC24 und
PIC32. Es macht da einfach gar keinen Sinn, etwas anderes als das
Microchip-Komplettpaket zu nehmen, weil es einfach Zeit spart und die
Arbeitszeit das eigentlich teure ist und nicht die Lizenzen.
Ich verdiene damit mein Geld. Es ist mir daher recht egal, ob der
Compiler frei gemäß GNU-Richtlinien ist oder nicht, weil die Kosten vom
jeweiligen Projekt getragen werden. Ich habe hier auch einen Kollegen,
der IAR für MSP430 benutzt, weil den Entscheidern das Risiko, dass bei
einem (nicht notwendigen) Wechsel irgendwas beim Kunden nachher nicht
mehr funktioniert, zu groß ist.
In einem universitären Umfeld wird das sicher anders sein als in einem
Unternehmen.
fchk
DerEgon schrieb:> In manchen Entwicklungsszenarien ist eine Zertifizierung nach> irgendwelchen Richtlinien erforderlich (MISRA, kann wohl von IAR geboten> werden).
Das dürfte in der Industrie ein Hauptgrund sein. Gegenüber den
Personalkosten spielen die Lizenzkosten keine ernsthafte Rolle. Ein
Compiler bzw. eine Ganze IDE mit "Stempel drauf" und integrierten Checks
schon.
Wir haben mal für den AVR den gcc Assebmler-Output gegenüber IAR AVR
verglichen, und uns dann ganz schnell für den IAR entschieden (okay
schon eine Weile her, das war 2012).
Entscheidend dürfte für die meisten professionellen Benutzer sein, ob
der Compiler/IDE-Hersteller einen "Guten Draht" zum
µC-Hersteller/Designer hat, und so möglichst schnell und gut die
Fähigkeiten oder Beschränkungen eines µC´s (oder einer Architektur)
auszunutzen.
Gruß
SDCC:
Schon die Dokumentation der Installation ist lückenhaft.
Er erfordert viele zu setzende Umgebungsvariable.
Die muss man "raten" und den Inhalt auch.
Welche Teile des Compilers und der Binuteils wohin gehören
ist das nächste Ratespiel.
Ich musste vor vielen Jahren MSC5 von Hand installieren,
weil der Installer mit der speziellen Grafikkarte nicht konnte.
Selbst das ging wesentlich einfacher.
Heizer schrieb:> Gegenüber den Personalkosten spielen die Lizenzkosten keine ernsthafte> Rolle.
Nicht unbedingt immer.
In meiner Zeit bei Atmel (auch schon eine Weile her) hat mich mal ein
Atmel-Mitarbeiter angesprochen, weil ein namhafter Kunde den IAR durch
AVR-GCC ablösen wollte. Der Grund: sie wollten gern nightly builds in
einer Serverfarm einführen (was man heute als "CI" bezeichnen würde),
und für eine solche Nutzung wären ihnen die IAR-Lizenzkosten explodiert.
Aber für die von Philipp genannten Targets dürfte sowas eher irrelevant
sein. Da ist ein AVR genauso wenig dabei wie ein ARM.
Bei meinem Ex-Chef ging es auch um Verantwortung, also der Lieferant von
der Software wird verantwortlich gemacht wenn irgendwas ist. Und dieses
irgendwas kann z. B. sein,
- wenn nach einem Update irgendwas nicht mehr läuft,
- wenn es beim Debuggen hakt und klemmt, dass die kurzfristig eine
Lösung erarbeiten (müssen),
- oder wenn man Sonderwünsche hat,
- ...
Jedenfalls gibt es jemanden, den man treten und ggf.
Schadensersatzpflichtig machen kann, wenn es nicht rund läuft und bei
den engen Terminen es zu Problemen kommt.
K. H. schrieb:> Jedenfalls gibt es jemanden, den man treten und ggf.> Schadensersatzpflichtig machen kann, wenn es nicht rund läuft und bei> den engen Terminen es zu Problemen kommt.
Und das hat je funktioniert und war nicht durch irgendwelche AGB eh
ausgeschlossen?
Das weiß ich nicht, jedenfalls war das die Begründung von unserem
(unfähigen) Gruppenleiter (GL). Ansonsten hätte unsere Fa. schon
mehrfach National Instruments (NI) in den Arsch treten müssen, aber ich
denke, unser GL hatte dazu keine "Eier in der Hose" und hat das Problem
erstmal auf die Kollegen abgewälzt, solange er sich aus Karrieregründen
die Finger nicht schmutzig macht. Also, wenn es hakt und klemmt sind die
eigenen Mitarbeiter erstmal Schuld und wenn die beweisen können, dass
sie nichts dafür können (ja, sie müssen ihre Unschuld beweisen), dann
sind sie irgendwie immer noch Schuld. Erst wenn man den unfähigen GL
wegen Verzögerungen anzählen könnte, wurde der aktiv und hat jemanden
aus unserer Gruppe damit beauftragt, bei Fa. NI nachzuhaken und Druck zu
machen. Das gab es als zusätzliche Aufgabe oben drauf, wir hatten ja
Zeit genug, eine Woche hat ja bis zu 148 mögliche Arbeitsstunden.
Jedenfalls was er Open Source Zeug gegenüber ziemlich voreingenommen,
das war bestenfalls Bastelware.
Übrigens hatten wir in solchen Sachen die meisten Probleme mit NI.
Philipp Klaus K. schrieb:> die vom Small Device C Compiler (SDCC) unterstützt werden
Wir hatten doch hier mal über die fehlende Eclipse Integration
gesprochen.
FTDI hatte ja einen Versuch gemacht, das Ergebnis war aber nicht
optimal, und inzwischen haben die ja aufgegeben:
https://www.ftdichip.com/old2020/Products/ICs/FT51.html
Silabs hat ja die Vereinbarung mit ARM/Keil für die kostenfreie Nutzung,
dennoch gab es einen Versuch mit Eclipse/Simplicity Studio und sdcc,
läuft aber bis Stand heute nicht:
https://community.silabs.com/s/question/0D51M00007xeGALSA2/add-the-sdcc-compiler-to-simplicity-studio
sdcc mag besser sein als Keil, aber wenn man dafür nicht aus
Eclipse/Simplicity Studio flashen/debuggen kann, und mit HEX Datei und
Bootloader anrücken muss ...
Philipp Klaus K. schrieb:> Es wäre schön, wenn die Antworten neben den Gründen auch die> jeweiligen Architekturen nennen würden.
Beide Beispiele beziehen sich auf den Z80. Haben zwar nichts mit den
kommerziellen Compilern zu tun, aber vielleicht hilft es ja trotzdem.
David Given (https://github.com/davidgiven/cpmish) wechselt von SDCC zu
ACK, unter anderem weil SDCC "buggy" ist. Der Code ist zwar wesentlich
schlechter, kann dafür aber 8080.
FUZIX (https://github.com/EtchedPixels/FUZIX) beschwert sich im Code oft
über SDCC-Bugs und entsprechende Workarounds. Allerdings ist Z80 auch
ein Primärtarget für das Projekt.
Was den kommerziellen Einsatz betrifft, liegen die Gründe eher in den
nicht-technischen Bereichen, die bereits genannt wurden.
Wir haben zwar nichts mit kleinen Controllern zu tun, aber nutzen Clang,
weil unsere Lieferanten das so vorschreiben. Würde da etwas anderes
dranstehen, würden wir auch etwas anderes nutzen, egal was es kostet. Da
hängen Haftungsfragen und Zertifizierungen dran, und jeder
Patch/Workaround in 3rd-party-code müsste von uns bis in die Ewigkeit
selbst gepflegt werden, weil "upstream" die vermutlich nicht integrieren
würde.
Linux hat sich auch so sehr lange geweigert, Clang-Fixes zu integrieren.
S. R. schrieb:> Philipp Klaus K. schrieb:>> Es wäre schön, wenn die Antworten neben den Gründen auch die>> jeweiligen Architekturen nennen würden.>> Beide Beispiele beziehen sich auf den Z80. Haben zwar nichts mit den> kommerziellen Compilern zu tun, aber vielleicht hilft es ja trotzdem.
Der z80-Port unterscheidet sich diesbezüglich deutlich von mcs51, sie
sind in gewisser Weise Gegenteile: Bei mcs51 gab es in den letzten
Jahren nur wenige Änderungen, die meisten davon Bugfixes. Und Bugs
werden dort nur sehr selten gefunden. Bei z80 gab es dagegen eine sehr
aktive Entwicklung, vor allem um Codegröße und -geschwindigkeit zu
verbessern.
Das führt dazu, dass im aktuellen Release 4.2.0 für mcs51 nahezu immer
fehlerfreier Code generiert wird, der aber nicht sonderlich effizient
ist. Für z80 wird dagegen deutlich effizienterer Code generiert;
bekanntwerdende Bugs für z80 werden meist zeitnah behoben, aber durch
die vielen Änderungen zur Verbesserung der Effizienz entstanden
natürlich auch mehr Bugs. Und wenn man, wie bei FUZIX üblich, mit einem
hohen Wert für --max-allocs-per-node kompiliert erhält man noch stärker
optimierten Code (um den Preis einer höheren Compilerlaufzeit, und
dessen, dass man dann SDCC auf eine Weise verwendet, die nicht so
ausführlich getestet wurde).
Allgemein ist SDCC aber in den letzten 2 Jahrzehnten deutlich
zuverlässiger geworden. Insbesondere hat SDCC auch eine großen Teil der
Testsuite von GCC übernommen, wodurch nochmal einige Bugs gefunden und
behoben wurden.
Vielen dank für die Antworten. Da es inzwischen hier und andernorts
einige gab, und nun nur noch sehr langsam weitere eintreffen, möchte ich
eine kurze Zusammenfassung geben.
Eine Antwort möchte ich hier in voller Länge zitieren, da sie sehr
direkt die beiden meistgenannten Gründe enthält:
"In my case the customer requested SDCC based project but it failed to
compile into the small flash size. Debugging was quite difficult. Using
the Simplicity Studio and Keil Compiler pairing made the code small
enough to fit into the device and made debugging much easier."
Die 3 meistgenannten Gründe gegen SDCC waren:
* Mangelnde Effizienz des von SDCC generierten Codes.
* Bessere Debugunterstützung und Integration der nichtfreien Toolchain.
* Verfügbarkeit bezahlten Supports für nichtfreie Compiler.
Meiner Meinung nach ist nun mittelfristig der aussichtsreichste Weg,
SDCC konkurrenzfähiger gegenüber nichtfreien Compilern zu machen:
0) Verbesserte maschinenunabhängige Optimierungen
1) Verbesserte maschinenabhängige Optimierungen für mcs51
2) Bessere Debugunterstützung und Integration
3) Finden und Beheben von Bugs.
Insgesamt schätze ich den Aufwand auf eine Vollzeitstelle für gut ein
Jahr. Aber auch mit weniger lässt sich natürlich einiges erreichen.
Punkt 2 Hätte eigentlich bereits im vom BMBF geförderten Projekt
SDCC-STD-UX angegangen werden sollen, wurde dann aber zugunsten
verbesserter Unterstützung für C2X zurückgestellt.
Jörg W. schrieb:>> Jedenfalls gibt es jemanden, den man treten und ggf.>> Schadensersatzpflichtig machen kann, wenn es nicht rund läuft und bei>> den engen Terminen es zu Problemen kommt.>> Und das hat je funktioniert und war nicht durch irgendwelche AGB eh> ausgeschlossen?
Bei automotive ist das normales Business, wenn der Tier 1 zum
vertraglich vereinbarten Zeitpunkt nicht liefern kann oder wegen nicht
zertifizierter Tool-Chain etwas passiert wirds teuer für ihn. Schneller
(d.h. mit garantierten Reaktionszeiten) Support bei Compilerfehlern ist
da auch wichtig.
Philipp Klaus K. schrieb:> Meiner Meinung nach ist nun mittelfristig der aussichtsreichste Weg,> SDCC konkurrenzfähiger gegenüber nichtfreien Compilern zu machen:
So, nun ist deine Katze aus dem Sack. Hättes es auch gleich sagen
können.
Man kann das auch kürzer sagen: der SDCC müßte in allen Punkten besser
werden, um mitspielen zu können.
Ich hatte sowas ähnliches vor Jahren mit dem GCC bei der Lernbetty
gemerkt. Im Vergleich zum Keil ist der GCC weitaus hakeliger in der
Benutzung, kann weniger, ist stellenweise inkompatibel zum Standard
(__irq und keine Pragmas Arm<-->Thumb) ist unverschämt (kürzt Schleifen,
die ICH geschrieben habe einfach weg), ist teilweise buggy (Problem
.thumb versus .thumbfunc) und machte dennoch einen umfänglicheren und
zugleich langsameren Maschinencode. Der einzige Pluspunkt ist der
fehlende Preis, was eigentlich nur für private Bastler wichtig ist. Er
hat dennoch seine Berechtigung, denn es heißt "besser schlecht gefahren
als gut gelaufen". So ähnlich sehe ich das auch beim SDCC.
W.S.
Philipp Klaus K. schrieb:> 1) Verbesserte maschinenabhängige Optimierungen für mcs51
Hallo Philipp,
manchmal treten aber mit steigenden Versionen auch Regressionen auf, die
mir z.B. bei einer zeitkritischen Anwendung auf die Füße gefallen sind,
SDCC 3.8 -> SDCC4.0:
https://github.com/Ho-Ro/Hantek6022API/issues/12
W.S. schrieb:> So, nun ist deine Katze aus dem Sack. Hättes es auch gleich sagen> können.
Das war beim Namen des Threadstarters aber von vornherein klar.
> Im Vergleich zum Keil ist der GCC weitaus hakeliger in der> Benutzung, kann weniger, ist stellenweise inkompatibel zum Standard> (__irq und keine Pragmas Arm<-->Thumb)
Was haben Implementierungs-Eigenheiten (alles, was mit zwei
Unterstrichen beginnt) und Pragmas mit "Standard" zu tun?
Wenn du dann noch den IAR ins Spiel bringst, wird der solche Dinge
nochmal anders handhaben – ist sein gutes Recht. Dinge wie das
Umschalten des Maschinenmodells oder Interrupts sind schlicht und
ergreifend eben kein Standard.
Ich hätte gern für mein aktuelles Projekt lieber den GCC genommen, aber
ich habe Herstellerbibliotheken mit ELF-Modulen, die Keil-proprietäre
Details enthalten (wenngleich ich gar nicht denke, dass sie das
bräuchten), und bei denen der GNU-Linker es daher als inkompatibel
ablehnt, sie zu linken. $$$ ist in dem Fall zwar nicht das Thema
(Lizenzen bezahlt $FIRMA), aber den ganzen Keil-uVision-Salat gibt's
halt nur für Windows, also muss ich ihn in einer VM laufen lassen, und
dort hat er sich wiederum hakelig damit, auf einem Netzwerklaufwerk zu
compilieren – er findet dann sämtliche Include-Files nicht.
Herstellersupport dafür? Kannste vergessen, "VM is not officially
supported" lautet die lapidare Antwort.
Ich weiß, ist off-topic hier, denn es war nach SDCC gefragt, aber zeigt,
dass es durchaus Kriterien geben kann, warum man einen kommerziellen
Compiler eigentlich gar nicht nehmen möchte aber nehmen muss. (Die MCU
ist völlig proprietär, und wahrscheinlich darf ich hier nicht einmal
schreiben, welche es ist, weil das schon unter NDA fällt.)
> Man kann das auch kürzer sagen: der SDCC müßte in allen Punkten besser> werden, um mitspielen zu können.
Nein. Die Antworten haben gezeigt, wo SDCC besser werden müsste.
Umgekehrt erkennt man daran aber auch, wo SDCC schon gut genug ist¹. Und
sie haben gezeigt, dass es durchaus möglich ist durch technische
Verbesserungen an SDCC die Position von SDCC gegenüber den nichtfreien
Compilern zu verbessern².
¹ Z.B. Hat sich niemand bezüglich SDCC über Compilerlaufzeit,
Ressourcenbedarf des Compilers oder mangelnde Unterstützung von
C-Standards beschwert.
² Es gab zwar durchaus einige, die sich aufgrund von Empfehlungen der
µC-Hersteller gegen SDCC entschieden, wegen mangelnder Unterstützung von
SDCC in Bibliotheken dritter, oder aufgrund mangelnder Zertifizierungen
von SDCC, aber das war eine Minderheit.
Philipp Klaus K. schrieb:> Z.B. Hat sich niemand bezüglich SDCC über Compilerlaufzeit,> Ressourcenbedarf des Compilers oder mangelnde Unterstützung> von C-Standards beschwert.
Wieder bezogen auf Z80: SDCC ist einfach sehr langsam, aber mangels
guter Alternativen muss man damit einfach leben. Da Programme in der
8-Bit-Welt naturgemäß nicht besonders groß sein können, bleiben auch die
Compilezeiten erträglich.
W.S. schrieb:> Ich hatte sowas ähnliches vor Jahren mit dem GCC bei der Lernbetty> gemerkt. Im Vergleich zum Keil ist der GCC weitaus hakeliger in der> Benutzung, kann weniger, ist stellenweise inkompatibel zum Standard> (__irq und keine Pragmas Arm<-->Thumb) ist unverschämt (kürzt Schleifen,> die ICH geschrieben habe einfach weg), ist teilweise buggy (Problem> .thumb versus .thumbfunc) und machte dennoch einen umfänglicheren und> zugleich langsameren Maschinencode.
Vielleicht solltest du dazu schreiben, dass du nicht in C
programmierst, sondern nur in einer Sprache, die ungefähr so ähnlich
aussieht.
W.S. schrieb:> ist unverschämt (kürzt Schleifen,> die ICH geschrieben habe einfach weg)
Das liegt an Deinen bekanntermaßen dürftigen C-Kenntnissen - nicht am
Compiler.
Nop schrieb:> Das liegt an Deinen bekanntermaßen dürftigen C-Kenntnissen - nicht am> Compiler.
Und du meinst, ein Compiler darf meine Kenntnisse über irgend etwas
abfragen und wenn es ihm nicht paßt, mir einfach mein Geschriebenes
wegstreichen? Nö, sowas akzeptiere ich nicht. Der Keil macht solche
Faxen übrigens nicht. Und der FCC911 übrigens auch nicht. Das ist der
für die Fujitsus. Seltsam, gelle? Ich sehe auch dieses Detail anders als
du, nämlich daß du und viele andere zu sehr an den GCC gewöhnt sind und
nun alles andere für Geisterfahrer halten. So herum.
W.S.
W.S. schrieb:> Und du meinst, ein Compiler darf meine Kenntnisse über irgend etwas> abfragen und wenn es ihm nicht paßt, mir einfach mein Geschriebenes> wegstreichen?
Ein C-Compiler darf (nicht: muß!) Dinge unter der as-if-Regel streichen,
wie das im C-Standard vorgesehen ist. Wenn Du den C-Standard nicht
kennst, d.h. Du kannst kein C, ist das Dein Problem und nicht das des
Compilers.
Er fragt keine Kenntnisse ab, sonder setzt das Verhalten um, was ihm in
der Programmiersprache beschrieben wurde. Da es kein C–Keyword für
„Warte mal kurz“ gibt, stellt er fest das die Schleife keine Änderung am
Programmzustand hervorruft und genau das übersetzt er dann dann in ein
„don‘t execute anything“. Und das so schnell wie irgend möglich.
Es gibt in C auch die Möglichkeit zu erklären, das da was passiert, was
der Compiler nicht sieht (volatile) und dann respektiert er das. Nur
hinschreiben muß es der Programmierer.
S. R. schrieb:> Philipp Klaus K. schrieb:>> Z.B. Hat sich niemand bezüglich SDCC über Compilerlaufzeit,>> Ressourcenbedarf des Compilers oder mangelnde Unterstützung>> von C-Standards beschwert.>> Wieder bezogen auf Z80: SDCC ist einfach sehr langsam, aber mangels> guter Alternativen muss man damit einfach leben.
Beim Z80 wären die Alternativen sdcc mit einem kleinen Wert für
--max-allocs-per-node, sowie zcc und ack. Die sind alle ebenfalls frei,
aber generieren üblicherweise schlechteren Code. Umgekehrt kann man sdcc
mit hohem Wert für --max-allocs-per-node oft noch langsamer machen und
dafür noch etwas besseren Code erhalten.
Philipp Klaus K. schrieb:> nichtfreie Compiler ... einsetzen.
Ist das nicht die gleiche Frage wie Linux/Windows, Libre/MS, Gimp/PS
etc?
Also Total_Cost_of_Ownership, Killerfeatures, Ausfallrisiko,
Integration, Kundenanforderungen, Gewohnheit, Schmiergeld (Seminare
etc.), ... nicht unbedingt in der Reihenfolge.
A. S. schrieb:> Ist das nicht die gleiche Frage
Nein, sie war deutlich konkreter gestellt, und wenn du dir den Rest des
Threads ansiehst, dann vor allem deshalb, weil Philipp offenbar wissen
möchte, an welcher Stelle er weitere Manpower am besten ansetzen sollte.
Gcc schrieb:> Er fragt keine Kenntnisse ab, sonderGcc schrieb:> Er fragt keine Kenntnisse ab, sonder...
Das ist mir klar, diese Bemerkung war auch nur zum Zwecke der
Vedeutlichung.
Um es mal klar zu sagen: von einem Compiler erwarte ich, daß er das, was
ich haben will, optimal von der Sprache der Notation in entsprechenden
Maschinencode übersetzt, aber NICHT, daß er an meinem Geschriebenen
herum mäkelt und nur dann, wenn es im Sinne seiner Programmierer ist,
das Zeug übersetzt.
Wenn das nicht gegeben ist, dann ist so ein Compiler nicht geeignet für
alle Firmware, die in irgend einer Weise mit Hardware zu tun hat. Und
ein Standard, der derartige Eigenmächtigkeiten sanktioniert, taugt nur
für die Tonne.
Aber zurück zum Thema, was man besser "warum nehmen die Leute nicht NUR
den SDCC?" hätte nennen können. Der Philipp schrieb:
> 0) Verbesserte maschinenunabhängige Optimierungen> 1) Verbesserte maschinenabhängige Optimierungen für mcs51> 2) Bessere Debugunterstützung und Integration> 3) Finden und Beheben von Bugs.
Tja, ist das nicht alles, wenn die Rede ist von einem Compiler?
Also, was denn sonst noch - außer Pillepalle?
W.S.
W.S. schrieb:> Um es mal klar zu sagen: von einem Compiler erwarte ich, daß er das, was> ich haben will, optimal von der Sprache der Notation in entsprechenden> Maschinencode übersetzt,
Soweit, so schön. Das macht annähernd jeder Compiler so, sofern er
nicht irgendwas zusammengefrickeles aus dem 1. Semester der
Informatik-Vorlesung ist.
> aber NICHT, daß er an meinem Geschriebenen herum mäkelt
Dann schalte halt alle Warnungen aus, wenn Du zu blöd bist, C
programmieren lernen zu wollen. Leb' dann aber auch mit den Ergebnissen,
ohne rumzuheulen.
> und nur dann, wenn es im Sinne seiner Programmierer ist,> das Zeug übersetzt.
Das ist drollig: Ein standardkonformer C-Compiler, der den Code (oder
Kot?) des Lernbetty-Großmeisters nicht so übersetzen will, wie es der
Herr Großmeister will, wird abgelehnt.
Wielange dauert es eigentlich noch, bis Du a) entweder C programmieren
lernst oder b) Dich anderen Dingen zuwendest?
W.S. schrieb:> Um es mal klar zu sagen: von einem Compiler erwarte ich, daß er das, was> ich haben will, optimal von der Sprache der Notation in entsprechenden> Maschinencode übersetztGenau das macht ein Compiler übrigens, wenn er
1
for(inti=0;i<10000;i++)
2
{/* nothing */}
zu nichts übersetzt, denn "nichts" ist sowohl von der Laufzeit als
auch vom Speicherverbrauch her die optimale Umsetzung einer Schleife,
die schlicht nichts macht. Die Zuweisung von Daten zu einer Variablen,
die man hinterher nicht wieder abfragt, ist eben halt aus Sicht eines
Compilers "nichts".
Jörg W. schrieb:> W.S. schrieb:>> Um es mal klar zu sagen: von einem Compiler erwarte ich, daß er das, was>> ich haben will, optimal von der Sprache der Notation in entsprechenden>> Maschinencode übersetzt>> Genau das macht ein Compiler übrigens, wenn er> 1 for (int i = 0; i < 10000; i++)> 2 { /* nothing */ }>> zu nichts übersetzt,
Der Compiler meint, daß es nichts sein soll. Man könnte so etwas als
eine Art Verzögerung einsetzen, da jeder Befehl eine bestimmte Anzahl
von Taktzyklen benötigt. Ob das am Ende guter Programmierstil ist sei
mal dahin gestellt, aber es würde vom Prinzip her funktionieren.
Vielleicht könnte der W.S. einfach mal ein Beispiel bringen.
Zeno schrieb:> Vielleicht könnte der W.S. einfach mal ein Beispiel bringen.
Der W.S. könnte auch einfach in C programmieren anstatt in einer
Programmiersprache, die nur so aussieht wie C. Das ist nämlich das
eigentliche Problem.
S. R. schrieb:> Der W.S. könnte auch einfach in C programmieren anstatt in einer> Programmiersprache, die nur so aussieht wie C. Das ist nämlich das> eigentliche Problem.
Wenn Du meinst.
Betty hilft auch hier nicht weiter schrieb:> Wer C programmieren kann, wüsste, wozu "volatile" verwendet werden kann.>> Wer sich hingegen weigert, dem hilft auch keine "Lernbetty".
Man muß ja mit W.S. nicht immer einer Meinung sein und in manchen Dingen
ist er sicher auch etwas speziell. Dennoch kann man sich ja auch das was
er z.B. mit der Lernbetty verbrochen hat ansehen. Ich habe das vor ein
paar Jahren mal getan und mir das ganze Betty Geraffel herunter geladen.
Es hat so funktioniert wie er es beschrieben hat - völlig problemlos vom
Compilieren der Quellen, Übertragen des Compilats auf die Betty und die
Funktion selbst. Also für einen der kein C kann nicht ganz schlecht. Die
Dokumentation zu seinem Projekt ist auch nicht schlecht gemacht, die
Mehrzahl solcher Projektdokumentationen, wenn es denn überhaupt welche
gibt, ist deutlich schlechter.
Ansonsten stell doch mal selbst ein solches Projekt auf die Beine und
beweise wie man es besser macht. Deine 2 Post in diesem Thread sind
bisher nur unqualifiziertes Geblöke ohne jegliche Substanz.
Zeno schrieb:> Der Compiler meint, daß es nichts sein soll. Man könnte so etwas als> eine Art Verzögerung einsetzen, da jeder Befehl eine bestimmte Anzahl> von Taktzyklen benötigt.
Es gibt aber in C keinen "Befehl", und es gibt auch keine
vorgeschriebenen Mindestausführungszeiten. Das würde letztlich der
Forderung nach möglichst optimaler Umsetzung des aufgeschriebenen Codes
zuwider laufen.
GCC hatte früher für diesen Konstrukt tatsächlich eine "Sonderlocke"
implementiert, aber das war zusätzlicher Aufwand, just diese Situation
("toter Code, der stehen bleiben soll") zu erkennen, und irgendwann
haben sie halt diese Sonderlocke abgeschafft.
Jörg W. schrieb:> Es gibt aber in C keinen "Befehl", und es gibt auch keine> vorgeschriebenen Mindestausführungszeiten. Das würde letztlich der> Forderung nach möglichst optimaler Umsetzung des aufgeschriebenen Codes> zuwider laufen.
Ach Jörg, jetzt hör mal mit dieser Erbsenzählerei auf, Du bist
intelligent genug um zu wissen worauf ich hinaus wollte. Ob man das nun
Befehl, Anweisung oder wie auch immer benennt ist am Ende doch völlig
Rille. Schlußendendlich macht der Compiler am Ende daraus eine Folge von
Instruktionen für die CPU die entsprechend umgesetzt werden. Für ein i++
sind nun mal eine bestimmte Anzahl von Taktschritten erforderlich um
dies umzusetzen, am Ende wird die weitere Befehlsausführung um genau die
Zeit die für die Ausführung erforderlich ist verzögert. Es könnte also
durchaus sein, das sich der Programmierer was dabei gedacht hat und
insofern wäre es schon wünschenswert, wenn der Compiler das umsetzt was
man hinschreibt, zumindest solange es sich um erlaubte Codesequenzen
handelt. Der Compiler kann ja in solch einem Fall eine Warnung ausgeben
und es dem Programmierer überlassen ob er es denn so stehen lassen will.
Zeno schrieb:> Für ein i++> sind nun mal eine bestimmte Anzahl von Taktschritten erforderlich um> dies umzusetzen, am Ende wird die weitere Befehlsausführung um genau die> Zeit die für die Ausführung erforderlich ist verzögert. Es könnte also> durchaus sein, das sich der Programmierer was dabei gedacht hat und> insofern wäre es schon wünschenswert, wenn der Compiler das umsetzt was> man hinschreibt, zumindest solange es sich um erlaubte Codesequenzen> handelt.
Diesen Thread habe ich begonnen, da SDCC-Entwickler nur wenig über jene
wissen, die SDCC nicht verwenden. Über die Nutzer von SDCC wissen wir
dagegen deutlich mehr, da diese ja über Mailinglisten, Tracker, etc mit
uns in Kontakt sind.
Nutzer mit obiger Ansicht gibt es durchaus, aber es ist eine kleine,
schrumpfende Minderheit. Ja, der Programmierer hat sich etwas gedacht,
als er das ++ schrieb. Aber heutzutage ist das ++ (oder was auch immer)
oft in einem Makro oder einer inline-Funktion, die dann mit konstanten
Parametern aufgerufen werden, die dann dazu führen, dass jenes ++ gar
nicht gebraucht wird. Und der Programmierer hat sich gedacht, dass das
kein Problem ist, da der Compiler es ja wegoptimieren kann, wenn es
nicht gebraucht wird.
Nur mal ein Beispiel: An SDCC wird häufig kritisiert, dass es jede
Funktion, die in einer Quellcodedatei steht, auch in die Binärdatei
kompiliert (wenn man also mehrere .c zu .rel kompiliert und diese dann
zusammenlinkt, ohne eine .lib zu verwenden), selbst wenn die betreffende
Funktion gar nicht aufgerufen wird. Da geht es also nicht mal um ein
einzelnes ++ oder eine leere Schleife, sondern um ganze Funktionen, von
denen die Programmierer erwarten, dass der Compiler diese wegoptimiert!
Zeno schrieb:> Es könnte also durchaus sein, das sich der Programmierer was dabei> gedacht hat
Wie Philipp schon schreibt: oft genug hat der Programmierer das nicht so
direkt hingeschrieben, sondern es versteckt sich innerhalb von irgendwas
anderem. Wenn du 'i = i * 2' schreibst, erwartest du ja auch nicht, dass
dann der (bei Fehlen von Multiplikationsbefehlen in der CPU in einer
Bibliothek sitzende) Code für eine Multiplikation mit 2 ausgeführt wird,
wenn der Compiler eigentlich auch feststellen kann, dass er stattdessen
viel einfacher nur ein Bit nach links schieben muss.
Wenn du zehnmal 'i++' ausführst, ohne dass das Ergebnis verwendet wird,
erwartest du auch keine 10mal ausgeführte Schleife, wenn die direkte
Addition einer 10 das gleiche tut.
So ist es eben auch, wenn du in einer Schleife irgendwas aufaddierst,
das am Ende gar nicht benutzt wird.
Verzögerungen jeglicher Art, insbesondere solche mit einem irgendwie
definierbaren Zeitverhalten, sind daher maschinenabhängig und lassen
sich nur entsprechend auf diesem Niveau implementieren. Ob man dafür nun
in die Schleife simpel einen "NOP" setzt oder ob es eine gut ausgefeilte
Infrastruktur dafür gibt (wie beim AVR-GCC, bei dem der Compiler
taktgenaue Verzögerungen nicht nur mit Schleifen sondern auch mit sauber
gezählten NOPs machen kann), es führt kein Weg dran vorbei, sich sowas
von Fall zu Fall selbst anzusehen statt den Compiler, von dem man
erwartet, dass er "optimal von der Sprache der Notation in
entsprechenden Maschinencode übersetzt" zu beschuldigen, dass er den
Code wegwirft, der aus seiner Sicht schlicht nichts macht.
Zeno schrieb:> Der Compiler kann ja in solch einem Fall eine Warnung ausgeben> und es dem Programmierer überlassen ob er es denn so stehen lassen will.
Die Warnung kannst du ja ganz leicht nachrüsten.
Einfach im Build-System zweimal kompilieren lassen, einmal mit -O0,
einmal mit -Os,-O2,-O3...
Dann die ausgeworfen Binaries vergleichen. Falls unterschiedlich:
"Warnung: Compiler hat optimiert!"
Zeno schrieb:> Für ein i++> sind nun mal eine bestimmte Anzahl von Taktschritten erforderlich
So funktioniert C ganz grundsätzlich nicht. Deswegen kann man das von
einem C-Compiler auch nicht erwarten.
> Es könnte also> durchaus sein, das sich der Programmierer was dabei gedacht hat
Dann hätte er "volatile" hinschreiben sollen. Wenn er das so wie W.S.
nicht weiß, hätte er vorher C lernen sollen.
> insofern wäre es schon wünschenswert, wenn der Compiler das umsetzt was> man hinschreibt
Nein. Nochmal, so funktioniert C nicht.
Jörg W. schrieb:> Wie Philipp schon schreibt: oft genug hat der Programmierer das nicht so> direkt hingeschrieben, sondern es versteckt sich innerhalb von irgendwas> anderem. Wenn du 'i = i * 2' schreibst, erwartest du ja auch nicht, dass> dann der (bei Fehlen von Multiplikationsbefehlen in der CPU in einer> Bibliothek sitzende) Code für eine Multiplikation mit 2 ausgeführt wird,> wenn der Compiler eigentlich auch feststellen kann, dass er stattdessen> viel einfacher nur ein Bit nach links schieben muss.
Jörg ich habe den Eindruck Du willst micht nicht verstehen und Dein
Vergleich hinkt auch.
Mir ist es völlig wurscht wie der Compiler 'i = i * 2' umsetzt. Ob er
dafür eine in der CPU evtl. vorhandene Multiplikationsinstruktion
benutzt oder einfach nur ein Bit nach links schiebt ist mir in diesem
Zusammenhang völlig egal. Ich erwarte schlichtweg das er den von mir
hingeschriebenen Quelltext, solange er gültigen Code darstellt, in
ausführbare Instruktionen für die CPU umsetzt, aber nicht entscheidet
das der hingeschriebene Code eigentlich, nach seiner Ansicht,
überflüssig ist und ihn deswegen einfach weg läßt. Der richtige Weg
wäre, daß er mir in so einem Fall mitteilt das ich diese Codesequenz
nochmals überdenken solle.
Compiler für andere Sprachen handhaben das anders und akzeptieren das
was der Programmierer hin schreibt.
Ich merke aber schon, das ich hier gegen Windmühlen kämpfe und die
Fangemeinde dieses Verhalten toll findet und lieber volatile
hinschreibt, um dem Compiler zu sage, mache es so wie ich es
hingeschrieben habe. So wird halt jeder auf seine Art glücklich. Mich
piept so etwas an und genau deshalb meide ich C wo es nur geht, aber
leider führt bei µC oftmals kein Weg daran vorbei.
Εrnst B. schrieb:> Die Warnung kannst du ja ganz leicht nachrüsten.> Einfach im Build-System zweimal kompilieren lassen, einmal mit -O0,> einmal mit -Os,-O2,-O3...> Dann die ausgeworfen Binaries vergleichen. Falls unterschiedlich:> "Warnung: Compiler hat optimiert!"
Du hast ja nun mal gar nicht verstanden worum es mir geht - macht aber
nichts.
Zeno schrieb:> Du hast ja nun mal gar nicht verstanden worum es mir geht
Nach deinen zusätzlichen Ausführungen oben: Doch, das habe ich exakt
verstanden. Ich hab mich nur darüber Lustig gemacht.
Nop schrieb:> So funktioniert C ganz grundsätzlich nicht. Deswegen kann man das von> einem C-Compiler auch nicht erwarten.> ...
Ja und genau deswegen fallen viele Anfänger erst mal so richtig auf die
Fresse.
Εrnst B. schrieb:> Ich hab mich nur darüber Lustig gemacht.
Also wieder mal die typische Arroganz der eingefleischten
C-Programmierer, die brauchen das ganz offensichtlich.
Zeno schrieb:> Ja und genau deswegen fallen viele Anfänger erst mal so richtig auf die> Fresse.
Nö. Die nehmen nämlich heutzutage Arduino, und da die
fix-und-fertig-rundum-glücklich "delay()"-Funktion.
Irgendwelche Zeitvertrödelungs-Schleifen baut da keiner mehr selber.
Zeno schrieb:> Ja und genau deswegen fallen viele Anfänger erst mal so richtig auf die> Fresse.
Oh. Eine Programmiersprache muß man tatsächlich lernen. Unglaublich, das
ist ja fast wie im richtigen Leben.
Zeno ist halt einfach ein paar Jahre zu früh dran.
Irgendwann, wenn die KI-Basierten Codegeneratoren ein Bewusstsein
entwickelt haben und brauchbare Ergebnisse liefern, kann auch er seinen
gedankenlesenden Do-What-I-Want Compiler haben.
Zeno schrieb:> Ich merke aber schon, das ich hier gegen Windmühlen kämpfe und die> Fangemeinde dieses Verhalten toll findet und lieber volatile> hinschreibt
Ja, natürlich. Die Freiheit, die der Compiler ganz absichtlich hat,
erlaubt ihm nämlich überhaupt erst etliche Optimierungen. Ob er die
Variable im Register hält oder auf dem Stack etwa - und beides wird die
Zeit so oder so erheblich beeinflussen. Genau dafür ist die as-if-Regel
da. Ganz einfach.
Das hat nichts mit "lieber volatile hinschreiben" zu tun, sondern damit,
daß auch Du auf einem ganz grundlegenden Level nicht verstehst, was C
überhaupt ist.
Zeno schrieb:> Ich erwarte schlichtweg das er den von mir hingeschriebenen Quelltext,> solange er gültigen Code darstellt, in ausführbare Instruktionen für die> CPU umsetzt, aber nicht entscheidet das der hingeschriebene Code> eigentlich, nach seiner Ansicht, überflüssig ist und ihn deswegen> einfach weg läßt
Dann darfst du ihn halt nicht optimieren lassen, -O0 als Option.
Dann macht er genau diese Tippeltappeltour und setzt alles 1:1 um. Das
Resultat ist halt riesig groß und schweinelangsam, aber es entspricht
dem, was du hingeschrieben hast.
Wenn du ihn dagegen optimieren lässt, dann sagst du ihm, dass er Dinge
einfacher ausdrücken soll, als sie hingeschrieben worden sind. Wenn du
nun einzelne Dinge doch nicht optimiert haben willst, musst du das dem
Compiler mitteilen. "volatile" wurde schon genannt, ich hatte auf die
Möglichkeit des Einstreuens von Inline-Assembler-Code (NOP) hingewiesen.
Wie sinnvoll das dann ist, darüber lässt sich natürlich vortrefflich
streiten, denn je nach CPU-Caching-Möglichkeiten kann das Resultat
trotzdem noch rasend schnell abgearbeitet werden.
Aber so ein "do what I mean"-Compiler, also "optimiere überall außer da,
wo ich mir gedacht (aber es nicht geschrieben) habe, dass du nicht
optimieren sollst" muss wohl erst noch erfunden werden.
Jörg W. schrieb:> Dann darfst du ihn halt nicht optimieren lassen, -O0 als Option.
Das ist allerdings Compiler-spezifisch, der C-Standard selber sieht
derlei nicht vor. Prinzipiell dürfte ein C-Compiler also auch bei
abgeschalteten Optimierungen solche Leerschleifen rauswerfen. Wenn der
Code mit Optimierungen kaputt ist, dann ist es es nämlich auch ohne
Optimierungen immer noch.
Nop schrieb:> Das ist allerdings Compiler-spezifisch, der C-Standard selber sieht> derlei nicht vor.
Ist natürlich richtig, aber ist dir schon mal ein Compiler über den Weg
gelaufen, der keine Möglichkeit hat, die Optimierungen abzuschalten? Ich
vermute, dass man das während der Implementierung eines Compilers
ohnehin benötigt.
Und auch der GCC unterlässt mit -O0 nicht alle Optimierungen
Sonst müsste am AVR eine Schleife
1
while(true)PINB|=(1<<1);
eine andere Frequenz ausgeben als
1
while(true)PINB|=(1<<7);
weil die Bitshifts am AVR unterschiedlich lange brauchen.
Aber der bösartige, verbrecherische Compiler setzt da trotz -O0 einfach
eine vorberechnete Konstante ein, obwohl es anders in Quelltext steht!
Jörg W. schrieb:> aber ist dir schon mal ein Compiler über den Weg> gelaufen, der keine Möglichkeit hat, die Optimierungen abzuschalten?
Nee, das nicht, aber wenn ich schon die Wahl habe, ob ich nach
C-Standard programmiere oder mich auf ein bestimmtes Verhalten eines
bestimmten Compilers verlasse, wähle ich Ersteres, weil Letzteres gerne
später zu Problemen führt.
Etwa mit Portabilität oder auch nur einem schnöden Compiler-Update. Ich
erinnere nur an die Story, wo GCC irgendwo bei 4.9 strict-aliasing zum
Default gemacht hat und Torvalds sich aufgeregt hat, weil das Kernel
Team erstens mit Pointer-Aliasing gearbeitet hatte sowie zweitens bei
der Build-Chain geschlampt und das nicht explizit angewiesen hatte. Dann
funktionierte es auf einmal nicht mehr.
Oder ganz typisch bei embedded: Mist, der Code paßt mit den neuen
Features nicht mehr ins Flash, laß mal mit -Os die Größe reduzieren.
Ooops, der auch vorher schon kaputte Code geht jetzt nicht mehr.
Nop schrieb:> laß mal mit -Os die Größe reduzieren.
Naja, wer im Embedded-Bereich nicht genau das von vornherein so macht,
der tut mir leid. Nicht optimierter Code auf dem PC ist schon Mist, aber
auf einem Controller ist es pure Geldverschwendung.
Jörg W. schrieb:> Naja, wer im Embedded-Bereich nicht genau das von vornherein so macht,> der tut mir leid.
Soviel also zum Thema "Optimierungen abschalten".
Also ich versteh den Zeno schon irgendwie. Es gibt Optimierungen, für
die man zumindest selber keine sinnvolle Anwendung sieht. Eine Schleife
wegzuoptimieren würde für mich dazu gehören. Aber es kann natürlich
sein, dass es die Anwendung doch gibt, Makros wurden hier ja schon
angedeutet, auch Konstanten könnten in einer Schleife verrechnet werden,
das dann der Compiler schon vollständig erledigen kann. Auch dass solche
grenzwertigen Spezialfälle vom Compiler als solche erkannt werden
müssten, was ein zusätzlicher Entwicklungsaufwand wäre, ist für mich ein
nachvollziehbares Argument.
Philipp Klaus K. schrieb:> An SDCC wird häufig kritisiert, dass es jede> Funktion, die in einer Quellcodedatei steht, auch in die Binärdatei> kompiliert [...], selbst wenn die betreffende> Funktion gar nicht aufgerufen wird. Da geht es also nicht mal um ein> einzelnes ++ oder eine leere Schleife, sondern um ganze Funktionen, von> denen die Programmierer erwarten, dass der Compiler diese wegoptimiert!
Das versteh ich gut. Man versucht ja wiederverwendbaren Code zu
schreiben bzw. versucht Code wiederzuverwenden und dazu gehört halt,
dass man auch Funktionen hat, die man im aktuellen Projekt gerade nicht
benötigt. Für Bibliotheken gilt das sowieso, auch wenn sie als Quellcode
vorliegen.
Maxe schrieb:> Eine Schleife> wegzuoptimieren würde für mich dazu gehören.
Aber optimieren, dass sie schneller läuft, darf er?
d.H. die Schleife in ein einziges "NOP" zu reduzieren wäre OK, sie ganz
wegzulassen ist nicht sinnvoll?
IAW: Wäre es für dich OK, wenn der Compiler aus
1
intsum=0;
2
for(inti=0;i<10;i++)sum+=i;
ein
1
intsum=45;
macht?
Oder ist das nicht sinnvoll?
Oder macht es dir Angst, dass der Compiler diese Optimierungsmöglichkeit
gesehen hat?
Nop schrieb:> Soviel also zum Thema "Optimierungen abschalten".
Naja, du warst doch derjenige, der unbedingt eine 1:1-Umsetzung haben
will.
Die geht, wenn man die Optimierung ausschaltet.
Ich bin nur derjenige, der sagt, dass ich das im Embedded-Bereich
nicht sinnvoll finde.
Jörg W. schrieb:> Naja, du warst doch derjenige, der unbedingt eine 1:1-Umsetzung haben> will.
Äh, nein? Das waren Zeno und W.S., während ich derjenige war, der sich
lieber an den C-Standard hält. Und Dein Vorschlag war es doch, mit -O0
die Optimierungen auszuschalten:
> Dann darfst du ihn halt nicht optimieren lassen, -O0 als Option.
Aber wenn man sich nicht an den C-Standard hält, meckert man, daß die
Optimierungen den Code kaputtmachen, obwohl er selbstverständlich schon
vorher kaputt war. Wenn man daher ohne Optimierungen arbeitet, anstatt
den Code zu fixen, dann rennt man später im Projekt u.U. genau in die
von mir beschriebene Situation: Code ist zu groß, und mit -Os geht er
nicht mehr.
Jörg W. schrieb:> GCC hatte früher für diesen Konstrukt tatsächlich eine "Sonderlocke"> implementiert, aber das war zusätzlicher Aufwand, just diese Situation> ("toter Code, der stehen bleiben soll") zu erkennen, und irgendwann> haben sie halt diese Sonderlocke abgeschafft.
Tja, aber in der typisch inkonsequenten Weise der C-"Logik" natürlich
nicht sehr konsequent.
Denn, in:
1
intmain(void){
2
3
while(1){
4
//nothing
5
}
6
}
wird die Schleife trotz ihrer offensichtlichen Nutzlosigkeit NICHT
wegoptimiert. Nach der von dir beschriebenen "superlogischen Logik", die
so typisch für dieses unsäglich erbärmliche C-Gefrickel ist, hätte sie
aber wegoptimiert werden müssen! Denn klarerweise geschieht im Body
nichts nützliches, d.h.: auch die diesen Body umfassende
Kontrollstruktur ist unnütz, denn eine Schleife, die unendlich garnix
macht, macht am Ende garnix.
Tja, so ist das mit der Logik...
c-hater schrieb:> hätte sie aber wegoptimiert werden müssen!
Nope. Ohne Endlosschleife gibt's nämlich einen beobachtbaren externen
Effekt: Das Programm endet. Bei den Delay-Schleifen gibt's so einen
Unterschied nicht. Erst denken, dann ranten.
Nop schrieb:> Nope. Ohne Endlosschleife gibt's nämlich einen beobachtbaren externen> Effekt: Das Programm endet. Bei den Delay-Schleifen gibt's so einen> Unterschied nicht. Erst denken, dann ranten.
Nur ist das Problem: an jeder anderen Stelle im Programm wird EXAKT
dieselbe Schleife wegoptimiert.
Was ist denn das für ein Sprachstandard? Einmal hüh, einmal hott bei
EXAKT demselben Sprachkonstrukt?
Das ist lächerlich für einen Sprachstandard!
Jörg W. schrieb:> Naja, du warst doch derjenige, der unbedingt eine 1:1-Umsetzung haben> will.>> Die geht, wenn man die Optimierung ausschaltet.
Moin,
bist Du sicher, dass der von Dir verwendete Compiler bei -O0 wirklich
den kompletten Code 1:1 übersetzt?
z.B. der C/C++ Development Guide zum IAR Compiler für Arm v9.30.1 sagt
auf Seite 250 zu den Optimierungen:
1
None (Best debug support)
2
- Variables live through their entire scope
3
- Dead code elimination
4
- Redundant label elimination
5
- Redundant branch elimination
Also wird bereits bei "Optimization = none" bis zu einem gewissen Punkt
nur das übersetzt, was am Ende auch Sinn macht und nach meinem
Verständnis sollte das vom C Standard (z.B. C99 - 5.1.2.3) abgedeckt
sein.
z.B. wird für das Incrementieren von foo kein Code mehr erzeugt, da die
Instruktion "unreachable" ist (aber es wird zumindest eine entsprechende
Warnung angezeigt):
1
intmain(void)
2
{
3
intfoo=123;
4
5
while(1){};
6
7
foo++;
8
}
@ Philipp:
Wie handhabt das denn der SDCC?
Gruß,
Michael
Michael F. schrieb:> bist Du sicher, dass der von Dir verwendete Compiler bei -O0 wirklich> den kompletten Code 1:1 übersetzt?
Naja, es wurde ja weiter oben schon angemerkt, dass insbesondere die
Konstantenberechnung trotzdem noch zur Compilezeit erfolgt. Bei dead
code elimination wäre ich mir jetzt nicht ganz so sicher, ich glaube,
die macht ein GCC (und vermutlich auch Clang) nur mit Optimierungsniveau
größer 0, da bei -O0 keinerlei Codeflussanalyse vorgenommen wird.
Übrigens sollte man dort zumindest schon aus diesem Grunde mit mehr als
-O0 arbeiten, denn eine ganze Reihe von Warnungen können sonst gar nicht
generiert werden …
Klar, der C-Standard äußert sich nicht zu Optimierungen, die sind da
"out of scope", da gilt die "as if"-Regel.
> kommt, kann natürlich wegoptimiert werden (non-reachable code).
Ja, das ist ja auch logisch und somit sinnvoll. Keine Einwände
meinerseits.
Ich meine sowas (absichtlich eingebauter "trap"):
1
if(errordetected){
2
while(true){
3
//nothing here: endless loop is INTENDED (as trap)
4
}
5
}else{
6
//perform the normal behaviour
7
}
Was tatsächlich rauskommt, ist aber, dass die gewollte Endlosschleife
ersatzlos rausoptimiert wird und statt dessen unmittelbar der Code
hinter dem Else-Zweig der Verzweigung ausgeführt wird.
Ist allerdings errordetected != true, wird erwartungsgemäß der "normal
behavior" durchlaufen (und macht auch, was er soll) und erst dann der
Code hinter der Verzweigung.
Εrnst B. schrieb:> Irgendwann, wenn die KI-Basierten Codegeneratoren ein Bewusstsein> entwickelt haben und brauchbare Ergebnisse liefern, kann auch er seinen> gedankenlesenden Do-What-I-Want Compiler haben.
Wieso muß der Compiler GEdanken lesen? Der soll nur machen was ich ihm
auf den "Einkaufszettel" schreibe.
Im Übrigen gibt es einen solchen Compiler schon seit ca. 1971. Der tut
das was ich ihm hin schreibe - ist halt kein C.
Jörg W. schrieb:> Warum sollte jemand, der sich "c-hater" nennt, sich mit C auskennen> (geschweige denn mit dessen Standard)?
Ich befürchte mal das sich der c-heater mit C besser auskennt als Du
denkst und nur durch die Besonderheiten diese Sprache zum c-hater
geworden ist.
Michael F. schrieb:> z.B. wird für das Incrementieren von foo kein Code mehr erzeugt, da die> Instruktion "unreachable" ist (aber es wird zumindest eine entsprechende> Warnung angezeigt):
So wäre das ja auch für mich in Ordnung - mit der Warnung, weil dann
entscheide ich ob an dieser Stelle "optimiert" wird oder nicht.
c-hater schrieb:> Was tatsächlich rauskommt, ist aber, dass die gewollte Endlosschleife> ersatzlos rausoptimiert wird und statt dessen unmittelbar der Code> hinter dem Else-Zweig der Verzweigung ausgeführt wird.
Ist das so? Gerade mal auf Godbolt geguckt für ARM-GCC 12.1 mit -O3.
Dieser Codeschnipsel hier...
1
volatileintdummy;
2
3
voidfunc(interrordetected)
4
{
5
if(errordetected){
6
while(true){
7
//nothing here: endless loop is INTENDED (as trap)
8
}
9
}else{
10
dummy++;
11
}
12
}
... wird compiliert zu:
1
func(int):
2
cbnz r0, .L3
3
movw r3, #:lower16:.LANCHOR0
4
movt r3, #:upper16:.LANCHOR0
5
ldr r2, [r3]
6
adds r2, r2, #1
7
str r2, [r3]
8
bx lr
9
.L3:
10
b .L3
11
dummy:
Es wird also die Endlosschleife ausgeführt, wenn errordetected ungleich
0 ist, und sonst die Dummy-Variable erhöht.
Ich vermute daher, daß in was auch immer Dein Beispiel ursprünglich
getan hat, der Fall des errordetected deswegen gar nicht auftreten kann,
weil Du dann undefined behaviour eingebaut hättest und der Compiler das
erkannt hat. Dann darf der Compiler diesen Fall behandeln, wie immer er
das möchte.
Das ist ein Fehler im Code, wenngleich C99 knapp 200 Fälle von undefined
behaviour hat und man das zurecht kritisieren kann, insbesondere weil
man nicht immer eine Warnung dazu bekommt. In dieser Hinsicht macht Rust
es besser.
c-hater schrieb:> Was ist denn das für ein Sprachstandard? Einmal hüh, einmal hott bei> EXAKT demselben Sprachkonstrukt?
Naja für die main() braucht man halt ab und an mal ne Endlosschleife um
goto zu vermeiden. Obwohl dafür gäbe es ja auch for(;;){} - ist genau so
hirnrissig.
Zeno schrieb:> Obwohl dafür gäbe es ja auch for(;;){} - ist genau so hirnrissig.
Nein, ist es nicht. Es ist deswegen die von K&R propagierte und die
einzige von Lint akzeptierte Form, weil man bei einer while-Schleife die
Schleifenbedingung aus Versehen auf endlos stellen kann, besonders im
Zusammenspiel mit Macro-Defines. Bei der Form mit for(;;){} gibt's
dieses Risiko nicht.
Zeno schrieb:> Ich befürchte mal das sich der c-heater mit C besser auskennt als Du> denkst
Diesen Eindruck hat er bei mir im Laufe der Zeit keineswegs
hinterlassen.
Nop schrieb:> Es wird also die Endlosschleife ausgeführt, wenn errordetected ungleich> 0 ist, und sonst die Dummy-Variable erhöht.
Zumal es derartige Endlosschleifen auch sonst immer mal gibt,
beispielsweise die default-Handler für allerlei Exceptions beim ARM sind
typischerweise genau sowas. Und die werden natürlich von keinem Compiler
weg optimiert.
Hier aus dem Atmel-ARM-Sourcecode:
1
/**
2
* \brief Default interrupt handler for unused IRQs.
Jörg W. schrieb:> Diesen Eindruck hat er bei mir im Laufe der Zeit keineswegs> hinterlassen.
Der Eindruck kann manchmal auch täuschen.
Nop schrieb:> Zeno schrieb:>> Obwohl dafür gäbe es ja auch for(;;){} - ist genau so hirnrissig.>> Nein, ist es nicht. Es ist deswegen die von K&R propagierte und die> einzige von Lint akzeptierte Form, weil man bei einer while-Schleife die> Schleifenbedingung aus Versehen auf endlos stellen kann, besonders im> Zusammenspiel mit Macro-Defines. Bei der Form mit for(;;){} gibt's> dieses Risiko nicht.
Ja logo finden die Fans der Sprache C so was geil, weil so etwas ohne
jegliche Logik ist, man muß es halt auswendig lernen.
Man kann jede Schleife zu einer Endlosschleife machen, wenn man die
Abbruchbedingung entsprechend setzt. Ob das wissentlich, versehentlich
oder gar gewollt gemacht wird ist dabei völlig Rille.
Zeno schrieb:> Man kann jede Schleife zu einer Endlosschleife machen, wenn man die> Abbruchbedingung entsprechend setzt.
Klar kannst du das.
Hier geht es ausschließlich darum, 1) welche Gepflogenheiten es (aus was
auch immer für Gründen) schon gibt und 2) was entsprechende
Syntaxchecker vorzugsweise erwarten. (Beides hängt natürlich zusammen.)
Das ist halt die "for (;;)"-Form, da sie praktisch nie versehentlich
"entstehen" kann.
Der eher seltene Fall einer Endlosschleife *) ist es gewiss nicht wert,
dass man ihm nun einen eigenen Sprachkonstrukt widmet – das wäre ja die
"offizielle" Alternative.
*) Im Kontext einer HDL sieht das anders aus, aber wir reden hier über
Programmiersprachen.
So ein Compiler kann schon unterscheiden zwischen einer Endlosschleife
und einer Schleife die nur eine (vermutlich danach nicht mehr
verwendete) Variable hochzählt. Ersteres soll nie enden, das letztere
soll so schnell wie möglich ausgeführt werden, als am besten mit 0
Takten. Und es gibt eine (indirekte) Möglichkeit dem Compiler zu sagen,
daß man den Zählvorgang doch haben will, vermutlich weil man Zeit
verbrennen will.
Wo ist also das Problem. Wer diese Sprache nicht mag, der soll es
einfach lassen. So wie ich die Sprache Baujahr 1971 nicht (mehr)
benutze, das aber normalerweise jedem verheimliche. Auch Fe2O3 brauch
ich nicht, aber auch das will ich niemandem erklären.
Gcc schrieb:> Wo ist also das Problem. Wer diese Sprache nicht mag, der soll es> einfach lassen. So wie ich die Sprache Baujahr 1971 nicht (mehr)> benutze
Genauso ist es, jeder soll auf seine Art glücklich werden.
Gcc schrieb:> das aber normalerweise jedem verheimliche
Warum das? Muß man sich rechtfertigen wenn man diese Sprache nicht mag?
Jörg W. schrieb:> Hier geht es ausschließlich darum, 1) welche Gepflogenheiten es (aus was> auch immer für Gründen) schon gibt und 2) was entsprechende> Syntaxchecker vorzugsweise erwarten. (Beides hängt natürlich zusammen.)> Das ist halt die "for (;;)"-Form, da sie praktisch nie versehentlich> "entstehen" kann.
Nun ja, Gepflogenheiten sind etwas, das nicht aus rationaler Überlegung
entsteht, sondern eben nur aus 'das mache ich nach'. So wie bei
Hobby-Tischlern, daß sie ihren Hobel NIE gerade auf ihren Basteltisch
stellen, sondern immer nur auf die Seite legen. Irrational? Ja. Eben wie
alle Gepflogenheiten. Aber herzlich egal.
Allerdings sieht das bei solchen Konstrukten wie for(;;) aus logischer
Sicht anders aus, als du es darstellst. Von einem Sprachkonstrukt
erwartet man eigentlich, daß es zu einem bestimmten Zweck existiert. So
ist der eigentliche Zweck von 'for' eben, eine abgezählte Schleife zu
machen und der von 'while' eine unabgezählte Schleife, aber mit einer
Abbruchbedingung. So etwas zu korrumpieren, indem man die Abzählung oder
die Abbruchbedingung hintertreibt, wird in C zwar nicht als
Programmierfehler gewertet, führt aber dennoch zu einer entarteten
Schleife, der ein wesentlicher Teil fehlt. Es ist unlogisch, ein
Sprachkonstrukt zu verwenden, dessen Zweck man garnicht bezweckt. Da
können K&R dazu sagen, was sie wollen. Was da bleibt ist eben nur die
Gepflogenheit. Und die ist irrational. Genauso wie der Streit darum, an
welchem Ende man das Ei aufschlägt.
W.S.
W.S. schrieb:> Allerdings sieht das bei solchen Konstrukten wie for(;;) aus logischer> Sicht anders aus, als du es darstellst.
Du hast nur eine Seite meiner Darstellung einbezogen – die andere Seite,
dass eine "for(;;)"-Schleife halt niemals "aus Versehen" (auch nicht
durch irgendwelche Makroerweiterungen etc.) entsteht, hast du ignoriert.
Diese dürfte aber wesentlich dazu beigetragen haben, dass diese
Gepflogenheit halt überhaupt so entstanden ist und dass sich
Syntaxchecker (wie Lint) daran orientiert haben, eine solche Schleife
nicht als potenziellen Programmierfehler zu warnen.
Kommt natürlich noch dazu, dass Endlosschleifen außerhalb von "deep
embedded" nur sehr selten benutzt werden. Es ist also mittelmäßig müßig,
sich nun ausgerechnet an solch einem Detail hier aufzugeilen. Es gibt
Dinge in C, die in die Kategorie "historisch gewachsen aber praktisch
nicht mehr zu ändern" fallen, die viel wesentlicher wären,
beispielsweise dass die Sichtbarkeit einer nicht näher auf Toplevel
einer Übersetzungseinheit bezeichneten Variablen oder Funktion global
statt modulintern ist. Aus heutiger Sicht hätte man das lieber anders
herum gehabt, also explizite Deklaration all dessen, was über den Modul
hinaus geht.
Zeno schrieb:> Gcc schrieb:>> das aber normalerweise jedem verheimliche> Warum das? Muß man sich rechtfertigen wenn man diese Sprache nicht mag?
Was hat das mit Rechtfertigung zu tun, wenn man nicht jedem seine
eigenen Vorlieben andienen will.
W.S. schrieb:> So ist der eigentliche Zweck von 'for' eben, eine abgezählte Schleife zu> machen
Nö. Eine Zählung mittels i++ in einer for-Schleife ist lediglich ein
Spezialfall einer Anwendung von einer for-Schleife. Das Konstrukt
"for" in C ist aber wesentlich allgemeiner gefasst. Die Verwendung einer
Zählvariablen in einer for-Schleife wird zwar der meiste Anwendungsfall
sein (weil es so am bequemsten ist), trotzdem ist dieses nicht der
"eigentliche Zweck".
Nur ein Gegenbeispiel von tausenden:
1
for(ptr=obj->start;*ptr;ptr=obj->next)
Wir sprechen hier nicht über Basic oder Pascal, wo eine for-Schleife
tatsächlich explizit bzw. implizit über eine Zählvariable läuft. Und ich
halte es auch für einen Fehler, Eigenschaften von anderen
Programmiersprachen auf C zu projizieren zu wollen. Das führt nur zu
einer Einschränkung - nämlich seines eigenen Denkapparates.
Martin H. schrieb:> Besser so?> for (ptr = obj->start; ptr && *ptr; ptr = ptr->next)
Sorry, ja, natürlich, wobei ich ptr alleine meinte - ohne Sternchen und
auch ohne die 2. Bedingung. Letztere kommt meist auf den Kontext an. :-)
Meine Antwort:
Beitrag "microchip c18 vs. sdcc"
Ich war noch zufrieden. Dann habe ich für meine Anwendungen einen
Interpreter entwickeln um möglich schnell zu Lösungen zu kommen.
Im Interpreter sind Menüs im Rom beschrieben. Und dann kam zum
Einsicht dieser Fehler:
https://sourceforge.net/p/sdcc/bugs/2589/
Zur Zeit keine Lösung. Trotzdem arbeite ich weiter mit SDCC.