Mikrocontroller: "Compiler-Optimizer-Fehler" finden?

On 16.03.2015 06:09, Reinhardt Behm wrote:

Das war ja auch eine große Neuerung bei den 32-Bit-Prozessoren, die es
vorher nicht gab - eine Vereinfachung fĂźr die Prozessorlogik.

Neu? das war schon bei der PDP11 so.
Das war auch damals schon der Grund, dass man char* nicht einfach nach int*
casten durfte.

Casten ist kein Problem. Aber Dereferenzieren :)

Viele Grüße,
Johannes


--
Wo hattest Du das Beben nochmal GENAU vorhergesagt?
Zumindest nicht Ăśffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos Ăźber RĂźdiger Thomas in dsa <hidbv3$om2$1@speranza.aioe.org>
 
Am 16.03.2015 um 23:04 schrieb Johannes Bauer:

> Casten ist kein Problem. Aber Dereferenzieren :)

Sicher. Aber in real-world-Source wird hauptsächlich aus 2 Grßnden gecastet:
1. um entsprechend zu dereferenzieren
2. Um falsche APIs zu befriedigen

Bernd
 
Hallo Reinhardt,

(wieder mehrere Antworten zusammengefasst.)

Du schriebst am Mon, 16 Mar 2015 13:15:08 +0800:

Java _ist_ eine C-basierte Sprache.

Nur weil die Leute, die Java implementieren keine andere Sprache als C
kennen und es dafĂźr benutzen, ist es noch lange nicht "C basierend".

Es ist C-_basiert_, nicht "-basiernd". Naja, Sprache...

Die _Syntax_ von Java ist der von C abgeschaut. Aber Du darfst durchaus
eine andere Definition von "basiert" definieren.


Du schriebst am Mon, 16 Mar 2015 13:10:38 +0800:

Nachdem in C von _jedem_ Datenobjekt die Adrese bestimmbar sein muß, ist
das so zu erwarten.

Du kennst keine bitfields? Davon gibt es auch keine Adresse.

Warum nicht? Sicher geht das. NatĂźrlich nur fĂźr die gesamte "struct", aber


Du schriebst am Mon, 16 Mar 2015 13:09:20 +0800:

Das war ja auch eine große Neuerung bei den 32-Bit-Prozessoren, die es
....
Neu? das war schon bei der PDP11 so.

Achja richtig - und die war nur 16-bittig. Die war allerdings keine
Mikroprozessormaschine, bei den Mikroprozessoren geb's das aber erst mit
den 32-Bittern.

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Hallo Ralf,

(wieder mehrerer Antworten zusammengefasst.)

Du schriebst am Sun, 15 Mar 2015 08:57:24 +0000 (UTC):

Ahemm. Bei Spielzeug-CPUs kĂśnnte deine Erwartung sich evtl. noch mit der
Realität decken. Bei modernen CPUs mit paralleler Ausfßhrung auf
mehreren internen Einheiten werden Befehle manchmal sogar noch innerhalb
der CPU umsortiert.

Ja, das ist der Grund dafür, daß die nicht echtzeitfähig sind und sich
schon garnicht fĂźr sicherheitskritsche aufgaben eignen - viel zu wenig
vorhersehbar im Verhalten.


Du schriebst am Sun, 15 Mar 2015 08:54:22 +0000 (UTC):

Nein, Aliasing ist prinzipiell unangenehem, da es auch die Verifikation
von Software erschwert. Die OptimierungsmĂśglichkeiten ergeben sich als

GenĂźgend lokalisiert noch nicht, aber wenn solche "Aliase" dann Ăźber's
ganze Programm versreut werden mit Sicherheit.

Nebenwirkung. Und wer damit Probleme hat, der hat vorher halt schon
schlechten Code produziert, dessen Korrektheit wohl nicht so ganz
einfach nachweisbar wäre.

Völlig richtig. Was aber nichts damit zu tun hat, daß es sinnvoll sein
kann, Variableninhalte situationsgemäß unterschiedlich zu interpretieren
(und zu verwenden), was der Ausgangspunkt der Diskussion war. Wenn die
Sprache dafßr _ßberhaupt keine_ (zu[ver]lässige) DarstellungsmÜglichkeit
bietet, ist sie fĂźr manche Anwendungen nicht geeignet - und dann ist ein
Wildwuchs von implementationsspezifischen "Ergänzungen" unvermeidlich.

So etwas ist bei Programmierern und Informatikern wohl Ăźblich, aber von
Ingenieuren hätte ich besseres erwartet.

Eher umgekehrt - Informatiker, falls sie sich als Programmierer betätigen,
können sich ihre Probleme (meistens) so hindrehen, daß solche
Uminterpretationen nicht nĂśtig sind. Ingenieure,als Programmierer, haben
meistens mit vorgegebenen Bauteilen und Gerätschaften zu arbeiten, die in
vorgegebener Weise zu verwenden sind. Daß diese in jedem Fall nahtlos
zusammenpassen ist eher nicht zu erwarten.

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Hallo Stefan,

Du schriebst am Mon, 16 Mar 2015 08:18:54 +0100:

Der Compiler darf Statements so umsortieren, wie er will, solange sich
das extern sichtbare Verhalten nicht ändert. Extern sichtbares Verhalten
ist definiert als im Wesentlichen: Zugriff auf volatile-Objekte und I/O.

Das reicht so noch nicht ganz - er muß schon auch Rücksicht nehmen auf
Variableninhalte - außer, Du siehst die auch als eine Art von "I/O" an.
Dann bleiben Dir aber fast nur noch Objekte, die in diese beiden Kategorien
fallen und Auswirkungen auf das extern sichtbare Verhalten haben.

....
Der geĂźbte C-Programmierer kennt die Fallstricke. Eine gute
Codierrichtlinie hilft auch dem ungeĂźbten Programmierer, die Fallstricke
zu vermeiden.

Ja, das ist eins der größeren Probleme von C, verursacht von seiner
Verbreitung und der zu häufigen Forderung, "das in C zu schreiben, weil da
jeder Programmierer damit zurecht kommt".

auch). Bei
a[++*p] = *q;
kann er das nicht mehr sehen. Da sind drei Zeiger beteiligt, und jeder
kann jeden anderen aliasen.

Genaugenommen nur zwei Zeiger, aber da C jeden Zeiger als Basis eines
Arrays ansieht, stimmt das dafßr. Nicht umsonst werden Zeiger häufig als
problematisch angesehen und sollen vermieden werden. Leider ist das in C
praktisch unmĂśglich, weil schon solche simplen Dinge wie Array-Zugriffe
und Variablen-Parameter hantieren mit Zeigern verlangen.

> Das ist kein Problem in einer VM-Sprache, die den Kram sowieso seriali-

(Was ist eine "VM-Sprache"?)

siert, und das ist auch kein Problem, wenn die Sprache entsprechendes
Aliasing ("ein int* zeigt auf die gleiche Speicherstelle wie ein int**")
nicht erst entstehen lässt.

Ja, hier gibt es halt ein Dilemma in C - Zeiger sind unvermeidbar, aber
sollen nach aller MĂśglichkeit vermieden werden...

....
Ansonsten darf der Compiler sehr wohl definieren, was beim undefinierten
Verhalten passiert. Dass das keiner tut, zeigt, wie sehr der Markt das
fordert.

Der _Compiler_ als Implementation einer Sprachdefinition _muß_ das
Verhalten definieren. Undefiniert lassen _kann_ es nur die Definition (der
"Standard").

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Hallo Johannes,

Du schriebst am Mon, 16 Mar 2015 23:01:51 +0100:

Du siehst es falsch, wenn du "undefinierte Fälle" fßr einen Fehler in
der Spec hälst. Das ist es ganz und gar nicht. Die
ImplementierungslĂźcken sind da mit *absoluter* Absicht, um es dem
Compiler zu ermĂśglichen, Ăźberhaupt bestimmte Optimierungen auszufĂźhren.

Dann hat das der Standard so zu enthalten. AFAIK _tut_ er das auch fĂźr
viele Fälle, wo angegeben wird, daß die Implementierung festzulegen hat,
wie gewisse AusdrĂźcke behandelt werden. Das sind dann _keine_ undefinierten
Fälle.

Zusätzliche Freiheitsgrade fßr den Compiler bedeuten aber eben auch,
dass der Benutzer wissen muss, was er tut. ...

Das sollte er allerdings immer.

extrem gut optimiert werden kann). Die Balance, die C da aber hält ist
meiner Meinung nach ausgesprochen gut gewählt - wie sich an der

Ich finde inzwischen eine sehr ausgeprägte Neigung zu "optimaler
Optimierung" vorherrschend.

> Popularität von C auch gut zeigt.

Die Popularität von C ergibt sich aus der relativen Anzahl der
Programmierer in den USA gegenßber anderen Ländern mit nennenswerter
Imformatik-Aktivität und inzwischen dem "IBM-Effekt" - der Forderung nach
der Verwendung eines mĂśglichst weit verbreiteten Verfahrens durch leitendes
(aber nicht notwendigerweise fachlich versiertes) Personal in Firmen.

Aber es funktioniert halt auch nicht, wenn ein Regelwerk, dessen
Einhaltung strikt erzwungen wird, große Löcher enthält.
....
Doch, funktioniert prima. Du musst aber um die LĂścher wissen, wenn du
die Sprache korrekt bedienen kĂśnnen willst.

Eben deswegen funktioniert es nicht. In der Realität treten eben auch Fälle
auf, die in ein Loch fallen - und dann bist Du entweder "angeschmiert" oder
mußt Dich auf eine bestimmte Implementation Deines Werkzeugs festlegen.

Beispiele sind beim gcc -fno-strict-aliasing oder -fwrapv (um die
Beispiele Abzudecken die hier im Thread vorkamen).

Womit die "eierlegende Wollmichsau" wieder ihre HĂśrner zeigt...

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Johannes Bauer schrieb:

Zusätzliche Freiheitsgrade fßr den Compiler bedeuten aber eben auch,
dass der Benutzer wissen muss, was er tut. Die eierlegende Wollmichsau
gibt es dabei aber leider nicht (100% idiotensichere Sprache die noch
extrem gut optimiert werden kann). Die Balance, die C da aber hält ist
meiner Meinung nach ausgesprochen gut gewählt - wie sich an der
Popularität von C auch gut zeigt.

FĂźr mich ist C ein high-level Assembler, speziell fĂźr DEC Maschinen. Bei
einer pdp-11 läßt sich ein C Programm ziemlich problemlos auch in
Assembler eingeben, weil die Adressierungsarten von Sprache und
Prozessor so gut zusammenpassen. Problematisch wird es eigentlich nur
mit CISC Prozessoren, deren Spezialbefehle in C entweder Ăźberhaupt nicht
ansprechbar sind, oder ohne heftige Optimierung ziemlich ineffizienter
Maschinencode herauskommen kann. Das gilt dann aber auch fĂźr jede
beliebige hĂśhere Programmiersprache, ist also kein Argument gegen C.

Fßr mich ist die wesentliche Schwäche von C die vÜllige Abwesenheit von
UnterstĂźtzung bei der Programm-Entwicklung, bezĂźglich Typsicherheit
(wegen Typecasts) und Überläufen in Ausdrücken und bei der Adressierung
(Ăźber Pointer). Auf PCs war es lange Zeit Ăźblich, mehrere C Compiler zu
benutzen: einen fĂźr die SyntaxprĂźfung mit ausfĂźhrlichen und
verständlichen Fehlermeldungen, einen zum Debuggen des Codes, und einen
fĂźr das fertige Programm.

Heute schafft man das vielleicht mit einem einzigen Compiler, die
Ursachen liegen aber im vĂśllig veralteten Sprachkonzept, mit
unhandlichen und damit fehlerträchtigen Deklarationen und Typecasts,
Mangel an Portabilität, unzusammenhängenden Quelltext-Modulen und
Header-Dateien, und dem Preprozessor, weshalb ein C Compiler 50% seiner
Zeit mit dem Scannen der Quelltexte verbringt.

Wer jetzt meint, daß C besonders portabel sei, weil es für jede Maschine
einen solchen Compiler gibt, der hat noch nie versucht, C Code von einer
solchen Maschine auf eine andere zu Ăźbertragen. Das scheitert meist
schon beim Compilieren mit anderen Standard-Bibliotheken, und bei
"portablen" Projekten sogar schon vorher, bei autoconfig :-(


Aber solange es nur um die Programmierung eines bestimmten (und
schmalbrĂźstigen) Mikrocontrollers (8 Bit Havard-Architektur) geht, ist C
(als high-level Assembler) durchaus erträglich. Doch sollte dann jeder
Programmierer auch seinen Prozessor gut kennen, damit er fĂźr schnellen
und kompakten Maschinencode auch die passenden Datentypen verwendet, und
durch sauberen Code keine Zweifel aufkommen lassen, was er gemeint hat.

<OT>
Wie sieht es eigentlich heute mit der Verbreitung von FORTH aus?

Ich habe damit jahrelang meine Microcomputer betrieben, vor allem wegen
der einfachen Portierung von einem Prozessortyp auf einen anderen. Aber
bei den heutigen Mikrocontrollern beschleicht mich der Verdacht, daß die
fßr FORTH nicht so richtig geeignet sind. Ansonsten hätte es mich schon
mal gereizt, FORTH auf meinem Arduino zu installieren...
</OT>

DoDi
 
Bernd Laengerich schrieb:
Am 16.03.2015 um 23:04 schrieb Johannes Bauer:

Casten ist kein Problem. Aber Dereferenzieren :)

Sicher. Aber in real-world-Source wird hauptsächlich aus 2 Grßnden
gecastet:
1. um entsprechend zu dereferenzieren
2. Um falsche APIs zu befriedigen
3. Um schlechten Compilern unter die Arme zu greifen

Als ich mich das zweite Mal mit C befaßt habe, und zum ersten Mal auf
einem PC, war ich von der Qualität der Microsoft-Entwicklungswerkzeuge
geradezu entsetzt. Nach Entfernen der vielen Typecasts aus den
mitgelieferten Beispielen, die vielleicht fĂźr MSC notwendig waren, nicht
aber fĂźr den BC, fĂśrderte der BC in jedem Beispiel kaum weniger als 50
haarsträubende Fehler zutage, in kaum mehr als 100 Zeilen Quelltext.
Neben den falschen Typecasts wimmelte es da nur so von unerreichbaren
Codeteilen aufgrund ĂźberflĂźssiger oder falsch formulierter Bedingungen
in "if" Statements. Seitdem wundert es mich nicht mehr, daß zu Windows
ständig neue Patches und Hotfixes erscheinen, mit denen wieder mal ein
Fehler durch zwei neue ersetzt wird :-(

Das Problem mit den mangelhaften Compilern scheint bei Microsoft zum
Geschäftsmodell zu gehÜren. Bei Visual Basic hat es mich fast zu Tränen
gerĂźhrt, wie verzweifelt die MS-Programmierer versuchten, Compilerfehler
durch haarsträubende Konstrukte in den Griff zu kriegen, weil der
Compiler sehr befremdliche Ansichten Ăźber den Umgang mit logischen
AusdrĂźcken und Booleschen Variablen und Werten hatte. Nach meinen
Untersuchungen zu VB3 wußte ich, daß es kaum Sinn macht, VB auch in
Maschinencode zu Ăźbersetzen. Trotzdem hat MS das versucht, mit dem
Erfolg, daß sich derselbe VB4 Quelltext völlig anders verhielt, wenn er
einmal in Bytecode und einmal in Maschinencode Ăźbersetzt wurde, und
vermutlich nochmal anders in den 16 Bit und (später) 32 Bit Versionen.

Anscheinend hat dann Jahre später jemand die Notbremse gezogen, und
Compilerbauer von Borland abgeworben, die ihr Handwerk bei Wirth gelernt
hatten. Die brachten dann mit .NET endlich mal eine ordentliche
Programmierumgebung heraus, die weitgehend frei war von den Schwächen
von C und sonstigen firmenspezifischen Schlampereien in den
Programmiersprachen und Compilern. Doch leider verkam diese solide
Grundlage dann durch die Firmenpolitik wieder zur Bedeutungslosigkeit,
was die weitere Verbreitung betrifft. Zum einen war das der
closed-source Code, verbunden mit ständigem Herumbasteln an den
unzureichend dokumentierten Systemfunktionen, was zum zweiten die
Wahrscheinlichkeit gegen Null gehen ließ, daß irgendwelche
(Hobby-)Programmierer als nĂźtzliche Idioten .NET auf andere
Betriebssysteme dauerhaft und erfolgreich Ăźbertragen kĂśnnen oder gar
dĂźrfen. So fĂźhrte auch bei Linux und anderen Unix-AbkĂśmmlingen weiterhin
kein Weg an C vorbei, wenn es um Standard-Bibliotheken und Tools geht,
und deshalb erfreuen sich dort auch so viele andere
(Interpreter-)Sprachen solcher Beliebtheit bei den
Anwendungsprogrammieren, weil sich damit geschriebene Programme einfach
auf beliebige Linux-Versionen (und andere Systeme) Ăźbertragen lassen.

<OT>
Bei Mikrocontrollern scheint neben C nur noch Java praktische Bedeutung
erlangt zu haben, wenn ich mich da auf meine Ăźblicherweise gut
informierten Quellen verlassen darf. Demnach soll es zu (fast) jedem
Mikrocontroller einen zertifizierten Java Compiler geben, der nicht nur
direkt Maschinencode erzeugt, sondern auch noch identische Ergebnisse
auf jedem Microcontroller produziert. Falls sich daran in den letzten
Jahren etwas geändert haben sollte, wäre ich fßr sachdienliche Hinweise
sehr dankbar.
</OT>

DoDi
 
Johannes Bauer wrote:

On 16.03.2015 06:09, Reinhardt Behm wrote:

Das war ja auch eine große Neuerung bei den 32-Bit-Prozessoren, die es
vorher nicht gab - eine Vereinfachung fĂźr die Prozessorlogik.

Neu? das war schon bei der PDP11 so.
Das war auch damals schon der Grund, dass man char* nicht einfach nach
int* casten durfte.

Casten ist kein Problem. Aber Dereferenzieren :)

Ja, wie beim Fall vom Hochhaus, das Fallen ist kein Problem, nur das Landen.
;-)

--
Reinhardt
 
Hallo Reinhardt,

Du schriebst am Mon, 16 Mar 2015 13:01:52 +0800:

Eine Variable hat immer einen Typ und der bestimmt, wie ihr Bitmuster zu
interpretieren ist.

Ja, aber der Typ bestimmt nur, wie ihr Inhalt im Kontext ihre Verwendung zu
interpretieren ist. Sobald die Variable an die "Außenwelt" kommt (das kann
schon durch Speichern der Fall sein), ist nur noch das Bitmuster sichtbar.

> Wie soll sie denn bitte gleichzeitig zwei Werte besitzen?

Sie hat jeden Wert, der ihrem Bitmuster zugeschrieben werden kann.

Zudem werden nie nicht Variable sondern AusdrĂźcke mit == verglichen. Wenn
^^^^^^^^^...
die AusdrĂźcke einen logischen Wert hat (also nur 0 oder 1, z.B. als
^^^^^^^^^^^^^ ^^^?
Ergebnis eines Vergleichs mit 0 wie oben), dann werden diese Werte
verglichen. Wenn Du da stattdessen int-Variable nimmst, dann werden deren
arithmetische Werte verglichen. Wo ist da jetzt das Problem?

Z.B. daß Du - in C - auch zwei Ausdrücke vergleichen kannst, die
_unterschiedliche_ Typen besitzen, z.B. einer einen arithmetischen und
der andere einen booleschen.

Mir scheint, die Typverwirrng ist eher in Deinem Kopf als in der Sprache
C. ^u

MĂśglich, C verursacht eben Verwirrung.

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Hans-Peter Diettrich wrote:
Aber solange es nur um die Programmierung eines bestimmten (und
schmalbrüstigen) Mikrocontrollers (8 Bit Havard-Architektur) geht, ist
C (als high-level Assembler) durchaus erträglich.

Aber nur wenn man *nicht* den GCC verwenden will.
 
Am 17.03.2015 um 05:04 schrieb Hans-Peter Diettrich:

Geschäftsmodell zu gehÜren. Bei Visual Basic hat es mich fast zu Tränen
[...]

Das merkwĂźrdigste was ich bei einem "geerbten" VB-Programm mal erlebt hatte,
war, daß aus einer API-Funktion, die letztlich einen DB-Zugriff ausführt, mal
das Programm wenige Zeilen später mit inkompatiblen Typen abstßrzte.
Nähere Untersuchung im Debugger zeigte dann, daß aus dieser Methode weder das
angeforderte Datenelement noch "Nothing" noch DBNull zurĂźckgeliefert wurde und
auch keine Exception in den try-catch-Ring geworfen wurde, sondern eine
Objektinstanz vom Typ Exception...

Ich glaube der Fehler verschwand irgendwann später aber die Abfangkonstruktion
mĂźsste da immer noch im Source sein.

Bernd
--
Meine Glaskugel ist mir leider unvorhersehbarerweise vom Balkon gefallen.
P.Liedermann in defa
 
Sieghard Schicktanz wrote:
Du schriebst am Mon, 16 Mar 2015 08:18:54 +0100:
Der Compiler darf Statements so umsortieren, wie er will, solange sich
das extern sichtbare Verhalten nicht ändert. Extern sichtbares Verhalten
ist definiert als im Wesentlichen: Zugriff auf volatile-Objekte und I/O.

Das reicht so noch nicht ganz - er muß schon auch Rücksicht nehmen auf
Variableninhalte - außer, Du siehst die auch als eine Art von "I/O" an.

Er muss nur dann RĂźcksicht auf Variableninhalte nehmen, wenn diese
Variablen irgendwann mal ausgegeben werden. In
for (int i = 0; i < 10; ++i) {
p = 42;
}
wird ein zeitgemäßer Compiler niemals eine Variable 'i' überhaupt
anlegen, und wenn, wird er sie hÜchstwahrscheinlich von 10 an abwärts
zählen lassen.

auch). Bei
a[++*p] = *q;
kann er das nicht mehr sehen. Da sind drei Zeiger beteiligt, und jeder
kann jeden anderen aliasen.

Genaugenommen nur zwei Zeiger, aber da C jeden Zeiger als Basis eines
Arrays ansieht, stimmt das dafßr. Nicht umsonst werden Zeiger häufig als
problematisch angesehen und sollen vermieden werden. Leider ist das in C
praktisch unmĂśglich, weil schon solche simplen Dinge wie Array-Zugriffe
und Variablen-Parameter hantieren mit Zeigern verlangen.

Das ist kein Problem in einer VM-Sprache, die den Kram sowieso seriali-

(Was ist eine "VM-Sprache"?)

"Eine Sprache, die mit einer VM implementiert ist."

Ansonsten darf der Compiler sehr wohl definieren, was beim undefinierten
Verhalten passiert. Dass das keiner tut, zeigt, wie sehr der Markt das
fordert.

Der _Compiler_ als Implementation einer Sprachdefinition _muß_ das
Verhalten definieren. Undefiniert lassen _kann_ es nur die Definition (der
"Standard").

Der Compiler muss es eben nicht definieren im Sinne von "da muss es
einen Absatz im Handbuch dazu geben". Also definiert er es als "das, was
im Zusammenspiel dieser 500000 Zeilen Compiler-Code rauskommt". Und das
heißt dann eben, dass sich das Verhalten von
a[++*p] = *q;
ändern kann, je nachdem, was in den 500 Quelltextzeilen davor und danach
steht.


Stefan
 
Am 17.03.2015 um 04:30 schrieb Reinhardt Behm:

> Ja, wie beim Fall vom Hochhaus, das Fallen ist kein Problem, nur das Landen.

Du musst Dich auf den Boden werfen - nur daneben.

Bernd
--
Meine Glaskugel ist mir leider unvorhersehbarerweise vom Balkon gefallen.
P.Liedermann in defa
 
Stefan Reuther schrieb:

Er muss nur dann RĂźcksicht auf Variableninhalte nehmen, wenn diese
Variablen irgendwann mal ausgegeben werden. In
for (int i = 0; i < 10; ++i) {
p = 42;
}
wird ein zeitgemäßer Compiler niemals eine Variable 'i' überhaupt
anlegen, und wenn, wird er sie hÜchstwahrscheinlich von 10 an abwärts
zählen lassen.


Ein ähnliches Testprogramm hatten wir mal zu einer Workstation bekommen,
und die Ergebnisse auf Konkurrenzprodukten waren durchaus interessant:
AIX 8 s
DG 8 min.
HP - nach 1 Stunde abgebrochen

Alles nur eine Frage der Optimierung. Beim AIX hat alleine die Ausgabe
des Ergebnisses (1 Zeile) anscheinend auch 8 min. gedauert, bei
unveränderten Optimierungs-Einstellungen - hatte offensichtlich ein
vĂśllig unbrauchbares I/O System ;-)

DoDi
 
Am 17.03.2015 um 02:17 schrieb Sieghard Schicktanz:

Z.B. daß Du - in C - auch zwei Ausdrücke vergleichen kannst, die
_unterschiedliche_ Typen besitzen, z.B. einer einen arithmetischen und
der andere einen booleschen.

Es gibt klare Regeln wie vorher auf einen Typ konvertiert wird.

Bernd
 
On 2015-03-13, Sieghard Schicktanz <Sieghard.Schicktanz@SchS.de> wrote:
Ok - die Optimiererei ist da sowieso ein eigenes Kapitel. Da müssen soviele
Annahmen getroffen werden, _was_ der aufgeschriebene Code-Text eigentlich
tun soll, daß es für den Optimierer(programmierer) recht schwierig ist, das
zu treffen, was der Code-Schreiber wollte. Das ist halt das "übliche"
Dilemma zwischen dem, was man _meint_ und dem was man "sagt", um es zu
beschreiben, "unmißverständlich", möglichst...

Nein. Der Optimizer hat Code zu erzeigen, der nach den angegebenen Kriterien
möglichst edffizient (=schnell oder kompakt) ist, die Randbedingungen gibt
der Sprachstandard vor. Was der Programmierer *gemeint* hat, ist irrelevant
- wenn er sich an den Sprachstandard hält, erzeugt der Optimizer das
- gewünschte Ergebnis, ansonsten ist der Quellcode fehlerhaft.

und das tut er halt in den wenigsten Fällen. Und sogar dann kann er die
Intention des Schreibers falsch verstehen. Kommt ja sogar unter Menschen
vor...

Nochmal: die Intention ist egal, es gilt der Sprachstandard. Im Rahmen
dessen darf der Optimizer alles tun, solange das gleiche Ergebnis
herauskommt.

uint16_t hash(uint32_t data)
{
uint16_t foo = *(uint16_t *) &data;

return foo[0] ^ foo[1];
}
Was der Compiler klassisch tun müßte, ist:
- data auf den Stack legen, um "&data" bestimmen zu können

Muß nicht per Stack passieren.

- die Adresse nehmen und 2 16-Bit Loads erzeugen und die Ergebnisse
XOR-verknüpfen

Nachdem in C von _jedem_ Datenobjekt die Adrese bestimmbar sein muß, ist
das so zu erwarten.
...
Nach meinem Bugreport hat man mir dann erklärt, daß der Compiler Recht
hat: foo und &data *dürfen* laut Sprachstandard nicht auf die gleiche
Adresse zeigen, also darf der Compiler das umsortieren.

Hat man Dir auch die Stelle im Sprachstandard genannt, an der das steht?

Ja - ist aber zu lange her. Die Baiss sind die aliasing-Regeln: ein
uint16-Zeiger *darf* nicht auf die gleiche Adresse zeigen wie ein
uint32-Zeiger, also darf der Compiler davon ausgehen, daß dem nicht so ist,
und entsprechenden Code erzeugen.

Das widerspricht schließlich direkt der Forderung nach der Adressierbarkeit
von Datenobjekten, der Konsistenz von Zuweisungen und der Einhaltung der
Reihenfolge der Anweisungen.

Nein, s.o..

Und hier sind die beiden Anweisungen durch die
Sequenzierung mit dem ";" sogar explizit in ihrer Reihenfolge festgelegt.
Aber hier gilt wohl schon das Gewohnheitsrecht der Optimiererprogrammierer
- der Optimierer hat immer Recht, auch wenn der erzeugte Code dem Source-
Text widerspricht.

Ja. Der erzeugte Code darf komplett anders aussehen als das, was im Source
steht, solange das gleiche Ergebnis herauskommt.

Das will man auch haben: es macht Sinn, z.B. Leseoperationen vorzuziehen,
damit die Werte im Register verfügbar sind ohne die Pipeline anzuhalten,
wenn sie weiter hinten gebraucht werden, oder Schreiboperationen nach hinten
zu schieben. Solange der Compiler sicherstellen kann, daß das Ergebnis das
gleiche ist wie das, was der Sprachstandard für den angegebenen Source
fordert, ist das legitim und im Interesse einer hohen Performance auf
modernen CPUs auch absolut notwendig.

Das geht natürlich nur, wenn der Compiler weiß, welche Daten unabhängig
voneinander sind - wenn 2 Zeiger in einer Situation auf die gleiche Adresse
zeigen können, und über den einen geschrieben wird, dann darf er eine
Leseoperation über den anderen Zeiger eben nicht vorziehen.

Aber zum Verständnis des Codes durch den Compiler: ein relativ aktueller
gcc "versteht" den Code soweit, daß er überhaupt nichts mehr auf den
Stack schiebt, und stattdessen
return (data ^ (data>>16);
erzeugt (was die korrekte Lösung ist und außerdem effizienter als das
Pointergefrickel, also sollte man das auch gleich so im Source
hinschreiben).

Ja, das wäre (beides) besser - aber was wolltest Du jatzt dazu schreiben?

Erstens, daß der Optimizer in aktuellen gcc den Code deutlich detaillierter
"versteht" als in älteren, und zweitens, daß man solche unportablen
Mikrooptimierungen (die in diesen Fall auch auf den alten Compilern zwar
korrekten, aber schlechten Code erzeugt haben) besser gleich bleiben läßt.

Dabei macht es keinen Unterschied, ob man die Zeiger per typecast oder
union umwandelt.

Eine union wandelt nur keine Zeiger um, sondern benutzt einen
Speicherbereich auf unterschiedliche Art. Wenn das benutzt wird, um
einen (Satz) Wert(e) in einer bestimmten Darstellung einzutragen (z.B. als
Felder eines Registers) und in einer anderen weiterzubearbeiten (z.B. um
das Register mit einem einzigen Zugriff beschreiben zu können), dann ist es
eben _sehr_ wichtig, was der Compiler und ggfs. ein Optimierer dann daraus
macht.

Nein, dann ist das unportabler Code. IIRC darf man aus einer Union nur exakt
den Typ auslesen, den man auch hereingesteckt hat.

Aber C - obwohl mal als "besserer Assembler" verschrien - entwickelt sich
immer mehr weg von der Hardware und wird, trotz solcher "Features" wie
"volatile", "static" oder "inline", immer weniger für solche Software
brauchbar, die nahe an der Hardware arbeiten müß.

Jein. Es fehlen schon immer ein paar Details, die man gerne hätte - z.B.
Strukturdefinitionen, deren Speicherabbild genau definiert ist, so daß man
die auf Peripherieregister mappen kann. Das fehlt aber schon immer.

Moderne Compiler decken durchaus mehr kaputten Code auf, aber kaputt war der
schon vorher.

cu
Michael
 
On 2015-03-14, Sieghard Schicktanz <Sieghard.Schicktanz@SchS.de> wrote:
Ein Optimierer, der sequenziell geschriebene Statements umsortiert, macht
mit Scherheit _nicht_, was der Programmierer erwartet, auch wenn trotzdem
(meistens) das richtige Ergenis herauskommen sollte.

Nein.

Der Optimizer darf statements beliebig umsortieren, solange das herauskommt,
was der Sprachstandard für den angegebenen Quelltext fordert.

Das kann dem Programmierer auch egal sein: es kommt das Ergebnis heraus, das
seinem Quelltext entspricht, mit korrektem Ergebnis.

Wenn es Dir auf die Reihenfolge ankommt, weil das eben keine
Speicheroperationen sind, sondern es Nebenwirkungen gibt (z.B. auf
Registern), dann mußt Du als Programmierer mit passenden Barrieren dafür
sorgen, daß an den kritischen Stellen nicht umsortiert wird.

Die brauchst Du allerdings auch bei einem Compiler, der überhaupt nichts
umsortiert, weil das heutzutage auch in Hardware passiert (Cache,
Speichercontroller etc. - auch dort kann ein Lesezugriff einen vorher
ausgeführten Schreibzugriff überholen!), das kannst Du also nicht dem
Compiler ankreiden.

cu
Michael
 
Hans-Peter Diettrich schrieb:

Das Problem mit den mangelhaften Compilern scheint bei Microsoft zum
Geschäftsmodell zu gehÜren.

Kann es sein, dass diese Meinung schon ein paar Jahrzehnte alt ist?
Afaik erzeugen aktuelle Versionen von MSVC ziemlich guten Code.

daß irgendwelche
(Hobby-)Programmierer als nĂźtzliche Idioten .NET auf andere
Betriebssysteme dauerhaft und erfolgreich Ăźbertragen kĂśnnen oder gar
dĂźrfen.

Mit Mono existiert schon seit Jahren eine freie open-source
Implementierung fĂźr viele Betriebssysteme, die wohl auch recht
erfolgreich ist. Auch Teile des Microsoft-eigenen .NET-Frameworks sind
open-source.

Christian
--
Christian Zietz - CHZ-Soft - czietz (at) gmx.net
WWW: http://www.chzsoft.de/
PGP/GnuPG-Key-ID: 0x52CB97F66DA025CA / 0x6DA025CA
 
Christian Zietz schrieb:
Hans-Peter Diettrich schrieb:

Das Problem mit den mangelhaften Compilern scheint bei Microsoft zum
Geschäftsmodell zu gehÜren.

Kann es sein, dass diese Meinung schon ein paar Jahrzehnte alt ist?
Afaik erzeugen aktuelle Versionen von MSVC ziemlich guten Code.

Das wollte ich auch garnicht bestreiten. Aber was nĂźtzt das, wenn die
Benutzer aus Tradition und Gewohnheit (C forever!) Kot (ab-)schreiben?

daß irgendwelche
(Hobby-)Programmierer als nĂźtzliche Idioten .NET auf andere
Betriebssysteme dauerhaft und erfolgreich Ăźbertragen kĂśnnen oder gar
dĂźrfen.

Mit Mono existiert schon seit Jahren eine freie open-source
Implementierung fĂźr viele Betriebssysteme, die wohl auch recht
erfolgreich ist. Auch Teile des Microsoft-eigenen .NET-Frameworks sind
open-source.

Auch da kann ich nur auf meine Erfahrung mit DotGNU zurĂźckgreifen,
damals war Mono noch ziemlich eingeschränkt, und *wesentliche* Teile des
..NET Frameworks closed bzw. aus rechtlichen GrĂźnden (clean room...)
nicht verwendbar. Alleine der Umstand, daß ständig neue und irgendwo
inkompatible Versionen von .NET (und anderer Software/Firmware anderer
Firmen) herauskommen, macht das Nachvollziehen dieser Änderungen viel zu
aufwendig, als daß man mit einem Nachbau damit Schritt halten könnte.
Ich gehe davon aus, daß genau das so beabsichtigt ist, wenn jemand mit
closed-source Code offensichtlich gewisse Interessen verfolgt.

DoDi
 

Welcome to EDABoard.com

Sponsor

Back
Top