Mikrocontroller: "Compiler-Optimizer-Fehler" finden?

Hallo Christian,

Du schriebst am Fri, 13 Mar 2015 20:51:08 +0100:

beiden Anweisungen durch die Sequenzierung mit dem ";" sogar explizit
in ihrer Reihenfolge festgelegt.

Nein! Da der Compiler davon ausgehen darf, dass 'foo' nicht auf 'data'
zeigt [1], kann er den Zugriff auf 'foo', das dann halt uninitialisiert

Also wieder mal ein Optimierungsproblem. Zugunsten der MĂśglichkeit, aus dem
vorgegebenen Code was zu machen, was nach irgendeinem Maß "einfacher" ist,
wird im Compilerbau anscheinend immer mehr vergessen, daß das, was da am
Ende 'rauskommt, auch was vernünftiges machen soll und daß das auch
einigermaßen vernünftig beschrieben werden können muß.

ist, auch vorziehen. Ein richtig schlauer Compiler optimiert die Routine
vermutlich gleich zu 'return 0;' um, denn wenn die zu lesenden Variable
eh uninitialisiert ist, kann die Routine ja ein beliebiges Ergebnis
zurĂźckgeben, also auch 0.

SchĂśn. Da ist dann scheint's das Endziel der Optimierung erreicht.
So ähnlich wurde auch schonmal ßber die Weiterentwicklungen der
Komprimierer gelästert, wo dann am Emde der ultimative Komprimierer alle
Dateien in ein einziges Byte packen wĂźrde...

(Bei hardwarenaher Software ist die Optimiererei jedenfalls immer recht
problematisch und ausschließlich nach vorheriger Prüfung des erzeugten
Assembler-Codes und unter der Vorgabe, nie eine andere Version der an
derErstellung beteiligten Programme zu verwenden, zulässig.)

--
--
(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 Fri, 13 Mar 2015 00:27:50 +0100:

D.h. der Compiler dĂźrfte sich aktiv dagegen wehren, eine solchen Zeiger
zu seinem Zweck benutzen zu wollen (zum Zeigen)?

DĂźrfte er.

Mit oder ohne Hinweis? Mit wäre ja noch zu verkraften, da kÜnnte man dann
drumrumarbeiten. Ohne wäre bÜse.

Aber ein "char *" _kĂśnnte_ inkompatibel zu einem anderen als "void *"
sein.

Nein. (ISO 9899:1999 §6.2.3.2p7, erlaubt im Wesentlichen das gleiche fßr

Dann ist das noch nicht in den gcc eingflossen - der gibt nämlich eine
Warnung aus, wenn z.B. einem "int *" ein "char *" zugewiesen wird, aber
nicht, wenn ihm ein "void *" zugewiesen wird. Naja, kann ja gut sein, die
man page weist ja selber darauf hin, daß das noch nicht vollständig ist.

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

Also wieder mal ein Optimierungsproblem. Zugunsten der MĂśglichkeit, aus dem
vorgegebenen Code was zu machen, was nach irgendeinem Maß "einfacher" ist,
wird im Compilerbau anscheinend immer mehr vergessen, daß das, was da am
Ende 'rauskommt, auch was vernünftiges machen soll und daß das auch
einigermaßen vernünftig beschrieben werden können muß.

Ja, soll der Compiler sich nun an den Standard halten oder lieber
herumraten, was der Nutzer (nicht-standardkonformes) von ihm will?

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

Du schriebst am Sat, 14 Mar 2015 22:41:19 +0100:

Sieghard Schicktanz schrieb:

Also wieder mal ein Optimierungsproblem. Zugunsten der MĂśglichkeit, aus
dem vorgegebenen Code was zu machen, was nach irgendeinem Maß
"einfacher" ist, wird im Compilerbau anscheinend immer mehr vergessen,
daß das, was da am Ende 'rauskommt, auch was vernünftiges machen soll
und daß das auch einigermaßen vernünftig beschrieben werden können muß.

Ja, soll der Compiler sich nun an den Standard halten oder lieber
herumraten, was der Nutzer (nicht-standardkonformes) von ihm will?

Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.
Ein Optimierer, der sequenziell geschriebene Statements umsortiert, macht
mit Scherheit _nicht_, was der Programmierer erwartet, auch wenn trotzdem
(meistens) das richtige Ergenis herauskommen sollte.
Sicher kann ein Standard alles mĂśgliche festlegen. Wenn die Festlegungen
aber zu unĂźbersichtlich werden, wird er impraktikabel.
Die angesprochene Regelung zur Zeigerkompatibilität ist sicher gut gemeint
- Zeigerfehler sind schließlich enorm problemträchtig - ist aber gegenüber
dem sonstigen Vorgehen (freie Typkonvertierung bei Zuweisungen)
inkonsistent und macht damit deren Verwendung unĂźbersichtlich.
(Aber das macht ja nichts, es hält sich ja k[aum ]ein Compiler dran...)

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Sieghard Schicktanz <Sieghard.Schicktanz@schs.de> schrieb:
Hallo Christian,

Du schriebst am Fri, 13 Mar 2015 20:51:08 +0100:

beiden Anweisungen durch die Sequenzierung mit dem ";" sogar explizit
in ihrer Reihenfolge festgelegt.

Nein! Da der Compiler davon ausgehen darf, dass 'foo' nicht auf 'data'
zeigt [1], kann er den Zugriff auf 'foo', das dann halt uninitialisiert

Also wieder mal ein Optimierungsproblem. Zugunsten der MĂśglichkeit, aus dem
vorgegebenen Code was zu machen, was nach irgendeinem Maß "einfacher" ist,
wird im Compilerbau anscheinend immer mehr vergessen, daß das, was da am
Ende 'rauskommt, auch was vernünftiges machen soll und daß das auch
einigermaßen vernünftig beschrieben werden können muß.

Nein, Aliasing ist prinzipiell unangenehem, da es auch die Verifikation
von Software erschwert. Die OptimierungsmĂśglichkeiten ergeben sich als
Nebenwirkung. Und wer damit Probleme hat, der hat vorher halt schon
schlechten Code produziert, dessen Korrektheit wohl nicht so ganz
einfach nachweisbar wäre.

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

Ralf
--
"ceterum censeo systemd esse delendam"

Ralf Döblitz * Schapenstraße 6 * 38104 Braunschweig * Germany
Mit UTF-8 kann man gleichzeitig äöüßÄÖÜæœłø‱¼½¾¤¹²³¢€£¥¶§¬÷×±©®™¡¿ verwenden …
 
Sieghard Schicktanz <Sieghard.Schicktanz@schs.de> schrieb:
[...]
Ein Optimierer, der sequenziell geschriebene Statements umsortiert, macht
mit Scherheit _nicht_, was der Programmierer erwartet, auch wenn trotzdem
(meistens) das richtige Ergenis herauskommen sollte.

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.

Ralf
--
"ceterum censeo systemd esse delendam"

Ralf Döblitz * Schapenstraße 6 * 38104 Braunschweig * Germany
Mit UTF-8 kann man gleichzeitig äöüßÄÖÜæœłø‱¼½¾¤¹²³¢€£¥¶§¬÷×±©®™¡¿ verwenden …
 
Sieghard Schicktanz wrote:
Du schriebst am Fri, 13 Mar 2015 00:27:50 +0100:
D.h. der Compiler dĂźrfte sich aktiv dagegen wehren, eine solchen Zeiger
zu seinem Zweck benutzen zu wollen (zum Zeigen)?

DĂźrfte er.

Mit oder ohne Hinweis? Mit wäre ja noch zu verkraften, da kÜnnte man dann
drumrumarbeiten. Ohne wäre bÜse.

"Undefiniertes Verhalten" heißt, der Compiler darf tun, was er will. Er
darf dir auch die Festplatte formatieren. Das wird er natĂźrlich nicht tun,
wenn er angemessene Verbreitung erlangen will. Aber frĂźhere gccs haben
in bestimmten Fällen (zugegeben nur implementation-defined) Nethack oder
Emacs gestartet.

Aber ein "char *" _kĂśnnte_ inkompatibel zu einem anderen als "void *"
sein.

Nein. (ISO 9899:1999 §6.2.3.2p7, erlaubt im Wesentlichen das gleiche fßr

Dann ist das noch nicht in den gcc eingflossen - der gibt nämlich eine
Warnung aus, wenn z.B. einem "int *" ein "char *" zugewiesen wird, aber
nicht, wenn ihm ein "void *" zugewiesen wird.

Enohyvfgvx orureefpufg qh wn fpuba tnam thg, ahe zvg qrz P haq qrz
Pbzcvyreonh uncreg rf abpu rva jravt.

Dass ein char* und ein void* kompatibel sind, sagt jetzt nichts darĂźber
aus, ob ein int* und ein char* kompatibel sind. Die sind es nicht und
sollen es auch nicht sein. Der gcc hat hier recht.


Stefan
 
Sieghard Schicktanz wrote:
Du schriebst am Sat, 14 Mar 2015 11:08:55 +0100:
Sicher. Es zeigt halt die Konsistenz der Sprache - "if (var1 == 0)" wird
als unschĂśn angesehen, man soll mĂśglichst "if (!var1)" schreiben,

...sagt jetzt wer?

Stand z.B. hier im Thread in <cm18jbFq954U1@mid.individual.net> effektiv da.
Christian schrieb zwar nicht 0, sondern "FALSE", was aber effektiv dasselbe
ist.

Nein, ist es eben nicht. Einmal ist von Integern die Rede, einmal von Bools.

Wenn man mit Null vergleichen will, schreibt man einen Vergleich mit
Null auf. Ganz einfach.

MISRA Rule 13.2 "Tests of a value against zero should be made explicit,
unless the operand is effectively Boolean."

Ist ein eingeschränkter Standard als Referenz fßr die ßbliche Nutzung
brauchbar?

MISRA kann durchaus als Basis fĂźr die Erstellung eigener Codierregeln
dienen.

Und ohne eigenen Regelsatz willst du keine Programmiersprache benutzen.
Das geht ja schon los mit "sind die Kommentare auf deutsch oder
englisch" und "wo legen wir eigentlich die Dateien ab".


Stefan
 
Sieghard Schicktanz wrote:
Du schriebst am Sat, 14 Mar 2015 22:41:19 +0100:
Sieghard Schicktanz schrieb:
Also wieder mal ein Optimierungsproblem. Zugunsten der MĂśglichkeit, aus
dem vorgegebenen Code was zu machen, was nach irgendeinem Maß
"einfacher" ist, wird im Compilerbau anscheinend immer mehr vergessen,
daß das, was da am Ende 'rauskommt, auch was vernünftiges machen soll
und daß das auch einigermaßen vernünftig beschrieben werden können muß.

Ja, soll der Compiler sich nun an den Standard halten oder lieber
herumraten, was der Nutzer (nicht-standardkonformes) von ihm will?

Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.

Macht er ja nicht. Der Compiler interpretiert den Quelltext anhand des
Sprachstandards.

Ein Optimierer, der sequenziell geschriebene Statements umsortiert, macht
mit Scherheit _nicht_, was der Programmierer erwartet, auch wenn trotzdem
(meistens) das richtige Ergenis herauskommen sollte.

Das Problem ist hier, dass Programmierer in den Quelltext Bedeutung und
damit Erwartungshaltung hineininterpretieren, die nicht drinsteht. Das
klassische Beispiel ist
a[i++] = i;

Zugegebenermaßen haben die C-basierten Sprachen da mehr Stolperstellen
als andere Sprachen. Aber von den anderen erwartet auch keiner, dass da
direkt ausfĂźhrbarer Maschinencode rauskommt, und da stĂśrt es dann auch
nicht, wenn jedes Objekt noch einen Hash (JavaScript) oder einen Mutex
(Java) zusätzlich ßbergeholfen bekommt.

Die angesprochene Regelung zur Zeigerkompatibilität ist sicher gut gemeint
- Zeigerfehler sind schließlich enorm problemträchtig - ist aber gegenüber
dem sonstigen Vorgehen (freie Typkonvertierung bei Zuweisungen)
inkonsistent und macht damit deren Verwendung unĂźbersichtlich.
(Aber das macht ja nichts, es hält sich ja k[aum ]ein Compiler dran...)

Es hält sich da eigentlich jeder Compiler dran.


Stefan
 
Am 15.03.2015 um 13:02 schrieb Stefan Reuther:

Dass ein char* und ein void* kompatibel sind, sagt jetzt nichts darĂźber
aus, ob ein int* und ein char* kompatibel sind. Die sind es nicht und
sollen es auch nicht sein. Der gcc hat hier recht.

Anekdote:
Ein Kollege hat seinerzeit mal ein Filetransferprogramm nach einer
externen Spec geschrieben. Und sich nach einem halben Jahr gewundert,
daß das Programm auf einer anderen Maschine zwar problemlos kompilierte,
aber reproduzierbar abstĂźrzte. Ich musste mir dann das Elend ansehen und
fand die folgende schĂśne Konstruktion:

1. Die empfangenen Eingabedaten wurden in einen unsigned char buffer
geschrieben.
2. Dann wurde mittels char* darauf zugegriffen um jeweils auf das
nächste Datenelement zuzugreifen
3. In den ersten Bytes waren jeweils Länge und Typ der folgenden Daten
kodiert. An dieser Stelle habe ich mich bereits gewundert, daß der
Kollege dabei offenbar den Byte-Sex beachtet hat, womĂśglich eine letzte
Verzweifelungsergänzung vor der Kapitulation
4. Je nach Typ wurde dann der char* auf int* oder long* gecastet und so
auf den Puffer zugegriffen.

Damals haben die Compiler fĂźr so etwas noch keine Warnungen geworfen,
aber der Prozessor (hier war es eine Power-Architektur RS/6000) eine
SIGSEGV.

Ich habe dann den Kram komplett umgeschrieben und es wurde dann wirklich
zeichenweise auf den Bytestream zugegriffen.

Bernd
 
On 15.03.2015 00:52, Sieghard Schicktanz wrote:

Ja, soll der Compiler sich nun an den Standard halten oder lieber
herumraten, was der Nutzer (nicht-standardkonformes) von ihm will?

Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.

Macht er ja nicht. Der Compiler macht das, was der Programmier ihm sagt.

Wenn der Programmierer also sagt "ich mĂśchte gerne undefiniertes
Verhalten" dann liefert der Compiler, wie bestellt. Das dem
Programmierer vielleicht nicht klar ist, dass er undefiniertes Verhalten
bestellt hat ist aber nicht das Problem des Compilers.

Der Compiler kann nur das machen, was der Programmierer ihm vorgibt. "Do
what I mean, not what I say" funktioniert halt nicht.

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>
 
Hallo Stefan,

nachdem das zum einen hier nicht so recht hereinpasst und zum anderen schon
reichlich umfänglich geworden ist, mÜchte ic mal bisserl kßrzen und
zusammenfassen.

Du schriebst am Sun, 15 Mar 2015 13:11:04 +0100:

[Optimierungsproblem]
Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.

Macht er ja nicht. Der Compiler interpretiert den Quelltext anhand des
Sprachstandards.

Jein - hier ist viel dem Optimieren zuzuschreiben. Besondern in dem
Beispiel mit den beiden aufeinanderfolgenden Statements sagt, soweit ich
das mitbekommen habe, der Standard eindeutig, daß solche eben nicht
umsortiert werden dĂźrfen.

Das Problem ist hier, dass Programmierer in den Quelltext Bedeutung und
damit Erwartungshaltung hineininterpretieren, die nicht drinsteht. Das

Weil ja _nur_ bzw. _erst_ der Programmierer einem Quellentext Bedeutung
nicht beimessen, sondern geben kann. Wenn dann die Sprachdefinition mehr
auf die Implementierbarkeit des Compilers als einer Anwendung ausgelegt
ist, dann ist es schon recht leicht, einmal eine Sonderlichkeit zu
Ăźbersehen, wenn man "nebenbei" auch noch eine vorgegebene Funktion zu
erreichen hat.

Zugegebenermaßen haben die C-basierten Sprachen da mehr Stolperstellen
als andere Sprachen. Aber von den anderen erwartet auch keiner, dass da
direkt ausfĂźhrbarer Maschinencode rauskommt, und da stĂśrt es dann auch

Wie bitte? Natürlich muß auch bei anderen Programmiersprachen (Pascal,
Ada u.ä.) direkt ausfßhrbarer Maschinencode rauskommen. Auch ohne subtile
Compiler- und Optimiereranpassungen der Sprachdefinition.

nicht, wenn jedes Objekt noch einen Hash (JavaScript) oder einen Mutex
(Java) zusätzlich ßbergeholfen bekommt.

Java _ist_ eine C-basierte Sprache.

Die angesprochene Regelung zur Zeigerkompatibilität ist sicher gut
gemeint
....
Es hält sich da eigentlich jeder Compiler dran.

NaschĂśn, ich kann da nur mit "meinem" gcc testen, und der schert sich
herzlich wenig um die Inkompatibilitätsforderung.


Du schriebst am Sun, 15 Mar 2015 13:02:13 +0100:

[Zeiger-Aliasing]
Mit oder ohne Hinweis? Mit wäre ja noch zu verkraften, da kÜnnte man
dann drumrumarbeiten. Ohne wäre bÜse.

"Undefiniertes Verhalten" heißt, der Compiler darf tun, was er will.

Ja, das ist auch so eine boshafte Eigenwilligkeit des C-Standards,
offengelassene Details explizit _nicht_ zu behandeln, z.B. als Hinweis oder
gar Warnung zu melden oder wenigstens zu ignorieren - nein, da darf
beliebig Schindluder getrieben werden.

....
Dass ein char* und ein void* kompatibel sind, sagt jetzt nichts darĂźber
aus, ob ein int* und ein char* kompatibel sind. Die sind es nicht und
sollen es auch nicht sein. Der gcc hat hier recht.

Dann ist aber die Behauptung falsch,
>>'void*' und 'char*' sind gleich mächtig.

Sie sind es eben _nicht_.


Du schriebst am Sun, 15 Mar 2015 13:05:43 +0100:

Sicher. Es zeigt halt die Konsistenz der Sprache - "if (var1 == 0)"
wird als unschĂśn angesehen, man soll mĂśglichst "if (!var1)" schreiben,
....
Nein, ist es eben nicht. Einmal ist von Integern die Rede, einmal von
Bools.

Das ist aber kein erkennbarer Unterschied - "FALSE" ist entweder eine
#define-Konstante oder ein enum-Element und wird dzf passend konvertiert.
Falls jetzt, wie angenommen, die verglichene Variable numerisch ist, ergibt
sich effektiv ein Vergleich mit der numerischen Konstante 0. Sogar mit
"#define FALSE (!(!0))", was ja eine boolesche Konstante "par excellence"
sein sollte.

....
Ist ein eingeschränkter Standard als Referenz fßr die ßbliche Nutzung
brauchbar?

MISRA kann durchaus als Basis fĂźr die Erstellung eigener Codierregeln
dienen.

Unbenommen, aber es ist ein _eingeschränkter_ 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 Sun, 15 Mar 2015 15:21:26 +0100:

Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.

Macht er ja nicht. Der Compiler macht das, was der Programmier ihm sagt.

Ein Musterbeispiel fĂźr den Sinnspruch "Computer machen nicht was man von
ihnen will, sondern was man ihnen sagt" - und das erbarmungslos.

Wenn der Programmierer also sagt "ich mĂśchte gerne undefiniertes
Verhalten" dann liefert der Compiler, wie bestellt. Das dem
Programmierer vielleicht nicht klar ist, dass er undefiniertes Verhalten
bestellt hat ist aber nicht das Problem des Compilers.

Es kann aber durch die Vorgaben fĂźr den Umgang mit dem Compiler - die
Sprachdefinition - dafür gesorgt werden, daß es möglichst wenig
undefinierte und möglichst keine mißverständlichen Fälle geben kann.

Der Compiler kann nur das machen, was der Programmierer ihm vorgibt. "Do
what I mean, not what I say" funktioniert halt nicht.

Aber es funktioniert halt auch nicht, wenn ein Regelwerk, dessen Einhaltung
strikt erzwungen wird, große Löcher enthält.
(Und komm' mir jetzt keiner mit GĂśdel!)

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

Du schriebst am Sun, 15 Mar 2015 14:45:05 +0100:

Dass ein char* und ein void* kompatibel sind, sagt jetzt nichts darĂźber
aus, ob ein int* und ein char* kompatibel sind. Die sind es nicht und
sollen es auch nicht sein. Der gcc hat hier recht.

Anekdote:
....
Damals haben die Compiler fĂźr so etwas noch keine Warnungen geworfen,
aber der Prozessor (hier war es eine Power-Architektur RS/6000) eine
SIGSEGV.

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

Sowas hatte ich auch mal. Eine lange bewährte Routine, die u.a. aus einem
Buffer einen Datenwert herausfischen mußte, funktionierte mit einer neuen
Gerätegeneration auf einmal nicht mehr. Die alten, intel-basierten Geräte
liefen nach wie vor einwandfrei, auf den neuen, mit ARM-Prozessoren, gab es
reproduzierbar AbstĂźrze.
Dummerweise lag halt der herauszufischende Datenwert, ein "DWORD", auf
einer _ungeraden_ Adresse... was der ARM mit einem Ausrichtungsfehler
quittierte. "Netterweise" wurde einem das aber nicht so mitgeteilt, sondern
es gab eine Fehlermeldung, aus der sich die Ursache partout nicht ersehen
ließ - Windows, halt. Ich habe da auch einiges an Zeit gebraucht, um die
Ursache zu finden. Beseitigt war sie dann schnell.

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

Hallo Reinhardt,

Du schriebst am Fri, 13 Mar 2015 06:47:49 +0800:

Irgendwie verstehe ich Dein Problem jetzt nicht. Wenn Du testen willst,
ob beide ==0 oder !=0 sind, dann schreibe es doch so hin:
res = (var1 == 0) == (var2 == 0);
Das liefert genau das gewßnschte Ergebnis und ist klar verständlich.

Sicher. Es zeigt halt die Konsistenz der Sprache - "if (var1 == 0)" wird
als unschĂśn angesehen, man soll mĂśglichst "if (!var1)" schreiben, aber an
anderen Stellen "schießt man sich damit in den Fuß". Man muß halt ständig
aufpassen, was der Compiler jeweils fĂźr Annahmen Ăźber den Typ der
AusdrĂźcke trifft, damit man am Ende nach der ganzen Konversions-Orgie ein
Ergebnis erhält, das dem erwarteten entspricht.

Die Diskussion startete mit der falschen Behauptung, C kenne keinen
Vergleich zwischen boolschen Werten. Das obige ist fĂźr mich ziemlich
zusammenkonstruiert.

Nein, das war _nicht_ die Behauptung. Die Behauptung war, C kann nicht
erkennen, ob ein Vergleich zweier Variabler ihren arithmetischen oder
ihren booleschen Wert (den sie jeweils _gleichzeitig_ besitzen) betreffen
soll.

Woher hast Du denn den Schnaps?
Eine Variable hat immer einen Typ und der bestimmt, wie ihr Bitmuster zu
interpretieren ist.

Wie soll sie denn bitte gleichzeitig zwei Werte besitzen?

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?

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

--
Reinhardt
 
Sieghard Schicktanz wrote:

Hallo Michael,

Du schriebst am 12 Mar 2015 23:07:04 GMT:

D.h. der Compiler dĂźrfte sich aktiv dagegen wehren, eine solchen Zeiger
zu seinem Zweck benutzen zu wollen (zum Zeigen)?
...
Ja - in dem Sinn, daß der Optimizer in so einem Fall nicht das erzeugen
muß, was Du eigentlich wolltest - im Extremfall bleibt von Deinem Code
nichts Ăźbrig.

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...

Der Compiler müßte dazu allerdings den Source-Text recht genau
"verstehen"

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...

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.

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

...
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?
Das widerspricht schließlich direkt der Forderung nach der
Adressierbarkeit von Datenobjekten, der Konsistenz von Zuweisungen und der
Einhaltung der Reihenfolge der Anweisungen. 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.
Andererseits ist C ja auch die Programmiersprache, die auf Compiler- und
Prozessor-Freundlichkeit optimiert ist.

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?

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.
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üß.
--
Reinhardt
 
Sieghard Schicktanz wrote:

Hallo Stefan,

nachdem das zum einen hier nicht so recht hereinpasst und zum anderen
schon reichlich umfänglich geworden ist, mÜchte ic mal bisserl kßrzen und
zusammenfassen.

Du schriebst am Sun, 15 Mar 2015 13:11:04 +0100:

[Optimierungsproblem]
Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen
hätte kÜnnen, und der Standard soll ihm die MÜglichkeiten dazu
mÜglichst beschränken.

Macht er ja nicht. Der Compiler interpretiert den Quelltext anhand des
Sprachstandards.

Jein - hier ist viel dem Optimieren zuzuschreiben. Besondern in dem
Beispiel mit den beiden aufeinanderfolgenden Statements sagt, soweit ich
das mitbekommen habe, der Standard eindeutig, daß solche eben nicht
umsortiert werden dĂźrfen.

Das Problem ist hier, dass Programmierer in den Quelltext Bedeutung und
damit Erwartungshaltung hineininterpretieren, die nicht drinsteht. Das

Weil ja _nur_ bzw. _erst_ der Programmierer einem Quellentext Bedeutung
nicht beimessen, sondern geben kann. Wenn dann die Sprachdefinition mehr
auf die Implementierbarkeit des Compilers als einer Anwendung ausgelegt
ist, dann ist es schon recht leicht, einmal eine Sonderlichkeit zu
Ăźbersehen, wenn man "nebenbei" auch noch eine vorgegebene Funktion zu
erreichen hat.

Zugegebenermaßen haben die C-basierten Sprachen da mehr Stolperstellen
als andere Sprachen. Aber von den anderen erwartet auch keiner, dass da
direkt ausfĂźhrbarer Maschinencode rauskommt, und da stĂśrt es dann auch

Wie bitte? Natürlich muß auch bei anderen Programmiersprachen (Pascal,
Ada u.ä.) direkt ausfßhrbarer Maschinencode rauskommen. Auch ohne subtile
Compiler- und Optimiereranpassungen der Sprachdefinition.

nicht, wenn jedes Objekt noch einen Hash (JavaScript) oder einen Mutex
(Java) zusätzlich ßbergeholfen bekommt.

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".

Die angesprochene Regelung zur Zeigerkompatibilität ist sicher gut
gemeint
...
Es hält sich da eigentlich jeder Compiler dran.

NaschĂśn, ich kann da nur mit "meinem" gcc testen, und der schert sich
herzlich wenig um die Inkompatibilitätsforderung.


Du schriebst am Sun, 15 Mar 2015 13:02:13 +0100:

[Zeiger-Aliasing]
Mit oder ohne Hinweis? Mit wäre ja noch zu verkraften, da kÜnnte man
dann drumrumarbeiten. Ohne wäre bÜse.

"Undefiniertes Verhalten" heißt, der Compiler darf tun, was er will.

Ja, das ist auch so eine boshafte Eigenwilligkeit des C-Standards,
offengelassene Details explizit _nicht_ zu behandeln, z.B. als Hinweis
oder gar Warnung zu melden oder wenigstens zu ignorieren - nein, da darf
beliebig Schindluder getrieben werden.

...
Dass ein char* und ein void* kompatibel sind, sagt jetzt nichts darĂźber
aus, ob ein int* und ein char* kompatibel sind. Die sind es nicht und
sollen es auch nicht sein. Der gcc hat hier recht.

Dann ist aber die Behauptung falsch,
'void*' und 'char*' sind gleich mächtig.

Sie sind es eben _nicht_.


Du schriebst am Sun, 15 Mar 2015 13:05:43 +0100:

Sicher. Es zeigt halt die Konsistenz der Sprache - "if (var1 == 0)"
wird als unschĂśn angesehen, man soll mĂśglichst "if (!var1)" schreiben,
...
Nein, ist es eben nicht. Einmal ist von Integern die Rede, einmal von
Bools.

Das ist aber kein erkennbarer Unterschied - "FALSE" ist entweder eine
#define-Konstante oder ein enum-Element und wird dzf passend konvertiert.
Falls jetzt, wie angenommen, die verglichene Variable numerisch ist,
ergibt sich effektiv ein Vergleich mit der numerischen Konstante 0. Sogar
mit "#define FALSE (!(!0))", was ja eine boolesche Konstante "par
excellence" sein sollte.

...
Ist ein eingeschränkter Standard als Referenz fßr die ßbliche Nutzung
brauchbar?

MISRA kann durchaus als Basis fĂźr die Erstellung eigener Codierregeln
dienen.

Unbenommen, aber es ist ein _eingeschränkter_ Standard.
--
Reinhardt
 
Sieghard Schicktanz 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.

--
Reinhardt
 
Sieghard Schicktanz wrote:
Der Compiler soll eben _nicht_ "herumraten", was der Nutzer wollen hätte
kĂśnnen, und der Standard soll ihm die MĂśglichkeiten dazu mĂśglichst
beschränken.

Macht er ja nicht. Der Compiler interpretiert den Quelltext anhand des
Sprachstandards.

Jein - hier ist viel dem Optimieren zuzuschreiben. Besondern in dem
Beispiel mit den beiden aufeinanderfolgenden Statements sagt, soweit ich
das mitbekommen habe, der Standard eindeutig, daß solche eben nicht
umsortiert werden dĂźrfen.

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.

Selbstverständlich darf der Compiler also bei 'a=1; b=2;' die
Reihenfolge der Zuweisungen beliebig wählen. Das darf er eigentlich in
jeder Programmiersprache.

Das Problem ist hier, dass Programmierer in den Quelltext Bedeutung und
damit Erwartungshaltung hineininterpretieren, die nicht drinsteht. Das

Weil ja _nur_ bzw. _erst_ der Programmierer einem Quellentext Bedeutung
nicht beimessen, sondern geben kann. Wenn dann die Sprachdefinition mehr
auf die Implementierbarkeit des Compilers als einer Anwendung ausgelegt
ist, dann ist es schon recht leicht, einmal eine Sonderlichkeit zu
Ăźbersehen, wenn man "nebenbei" auch noch eine vorgegebene Funktion zu
erreichen hat.

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

Die Fallstricke entstehen nicht, weil jemand faul war, sondern weil die
entsprechenden Probleme einfach nicht erkennbar sind. Bei
a[++i] = i;
kann der Compiler noch sehen, dass da was faul ist (und der gcc warnt
auch). Bei
a[++*p] = *q;
kann er das nicht mehr sehen. Da sind drei Zeiger beteiligt, und jeder
kann jeden anderen aliasen.

Das ist kein Problem in einer VM-Sprache, die den Kram sowieso seriali-
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.

nicht, wenn jedes Objekt noch einen Hash (JavaScript) oder einen Mutex
(Java) zusätzlich ßbergeholfen bekommt.

Java _ist_ eine C-basierte Sprache.

Es sieht auf den nullten Blick nicht ganz von C verschieden aus, ist
aber tatsächlich etwas vollkommen anderes (VM-Sprache, keine
Zeigerarithmetik, komplett anderes Modularisierungskonzept). Das hat es
mit JavaScript, awk, Perl oder PHP gemein: die sehen auf den nullten
Blick auch nicht ganz von C verschieden aus.

Mit oder ohne Hinweis? Mit wäre ja noch zu verkraften, da kÜnnte man
dann drumrumarbeiten. Ohne wäre bÜse.

"Undefiniertes Verhalten" heißt, der Compiler darf tun, was er will.

Ja, das ist auch so eine boshafte Eigenwilligkeit des C-Standards,
offengelassene Details explizit _nicht_ zu behandeln, z.B. als Hinweis oder
gar Warnung zu melden oder wenigstens zu ignorieren - nein, da darf
beliebig Schindluder getrieben werden.

Ich habe bereits zitiert, wo auch Pascal undefiniertes Verhalten zulässt.

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


Stefan
 
On 15.03.2015 22:03, Sieghard Schicktanz wrote:

Es kann aber durch die Vorgaben fĂźr den Umgang mit dem Compiler - die
Sprachdefinition - dafür gesorgt werden, daß es möglichst wenig
undefinierte und möglichst keine mißverständlichen Fälle geben kann.

Genau. Und deswegen gibt es ja zum Beispiel die Java
Sprachspezifikation, in der vieles ganz anders läuft als bei C. Aber bei
C gibt's das halt nicht.

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.

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.

Der Compiler kann nur das machen, was der Programmierer ihm vorgibt. "Do
what I mean, not what I say" funktioniert halt nicht.

Aber es funktioniert halt auch nicht, wenn ein Regelwerk, dessen Einhaltung
strikt erzwungen wird, große Löcher enthält.
(Und komm' mir jetzt keiner mit GĂśdel!)

Doch, funktioniert prima. Du musst aber um die LĂścher wissen, wenn du
die Sprache korrekt bedienen kĂśnnen willst.

Aber du bist nicht alleine, wenn du die Balance ein bischen zu sehr zu
Gunsten der Performance und zu wenig zu Gunsten des Benutzers siehst.
Und deswegen gibt es zahlreiche Compiler-Optionen, um die Regeln ein
bischen einzuschränken. Dann wird eben in bestimmten Fällen schlechteter
Code generiert.

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

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>
 

Welcome to EDABoard.com

Sponsor

Back
Top