Mikrocontroller: "Compiler-Optimizer-Fehler" finden?

Heinz Saathoff wrote:
Edzard Egberts schrieb:

Sieghard Schicktanz wrote:
#include <stdio.h
#include <stdbool.h

int main (int argc, char * argv [])
{
bool b, c;
int i, k;

b= !c;

Das ist undefiniertes Verhalten, da c nicht initialisiert ist. Eine

Hier war b "zufällig" anfangs 0

Das ist aber ein großer Zufall, nämlich 1:254. bool wird intern ja
meistens in ein Byte gepackt, nicht in ein Bit und der Operator '!' ist
bei bool meistens als bitweise Invertierung der gesamten Variablen
implementiert.

Welcher Compiler macht denn sowas? Das ist ja eine fehlerhafe
Umsetzung des Operators !

Bei dem Effekt bin ich mir sicher, bei meiner Erklärung nicht so. Kann
auch sein, dass der ! nur das Bit Null invertiert (halte ich sogar für
wahrscheinlicher als meine vorhergehende "komplett invertieren" Deutung,
weil das mit den Werten 0 / 1 besser hinkommt) und die Abfrage dann
wegen der anderen Bits durcheinander kommmt.

> Was würdest Du hier erwarten:

Ein Beispiel mit nicht initialisierten Bool-Werten.

bool a, b;
while (a!= b)
{
cout << "a!= b" << endl;
a= !a;
}
 
Edzard Egberts wrote:
Ein Beispiel mit nicht initialisierten Bool-Werten.

bool a, b;
while (a!= b)
{
cout << "a!= b" << endl;
a= !a;
}

Im Debug-Modus finden übrigens bei manchen Systemen
Default-Initialisierungen statt (normalweise Null), also bitte als
Release testen.
 
Heinz Saathoff wrote on Mon, 15-03-09 13:38:
>Alles andere als 1 0 0 0 ... wäre falsch.

Sicher? Ich kenne NOT nur als bitweise Operation.
 
Edzard Egberts schrieb:

Was würdest Du hier erwarten:

Ein Beispiel mit nicht initialisierten Bool-Werten.

bool a, b;
while (a!= b)
{
cout << "a!= b" << endl;
a= !a;
}

Das Problem ist hier die nicht initalisierte Variable b und damit der
Verleich in der while-Bedinging.
Der Operator ! bei a = !a macht schon, was er soll, so wie Reinhard
das beschrieb.
BTW, in C++ kannst Du auch dies scheiben:
int var = 123;
bool b = var;
int i = b;
und b wird anschließend den Wert true haben und i den Wert 1.
Ob das in C auch definiert ist, weiß ich im Moment nicht.


- Heinz
 
Am Sun, 08 Mar 2015 19:15:26 +0100 schrieb Stefan Reuther:

bool b, c;
int i, k;

b= !c;

Das ist undefiniertes Verhalten, da c nicht initialisiert ist.

Hat wahrscheinlich nur funktioniert, wel der Stack in main () noch leer
war ...
Oder werden inzwischen auch auto-Variablen zu 0 initialisiert?

Eine uninitialisierte bool-Variable kann auch einen Wert haben, der
weder true noch false ist.

Wenn b wirklich eine bool-Variable wäre, kÜnnte sie nur einen der beiden
Werte "true" und "false" (rsp 0 / 1) annehmen und wäre genau ein Bit
breit. So wie ein 8-Bit "unsigned char" nur Werte zwischen 0 und 255
annehmen kann.

Ade

Reinhard
 
Hallo Edzard,

Du schriebst am Mon, 09 Mar 2015 11:35:26 +0100:

Hier war b "zufällig" anfangs 0

Das ist aber ein großer Zufall, nämlich 1:254. bool wird intern ja
meistens in ein Byte gepackt, nicht in ein Bit und der Operator '!' ist

Äh? Was für Bytes benutzt _DU_ denn?

Die Bytes, die ich kenne, bestehen Ăźblicherweise aus 8 Bits mit dzf.
insgesamt 2^8 = 256 möglichen Werten. Daß ein solches Byte _zufällig_ den
Wert 0 hat, hat bei Gleichverteilung der Werte also die Wahrscheinlichkeit
1/2^8 = 1/256. 1/254 wäre nur mÜglich, wenn genau 2 Werte nicht angenommen
werden kĂśnnen, aus welchen GrĂźnden auch immer.

bei bool meistens als bitweise Invertierung der gesamten Variablen
implementiert. So lange c also nicht zufällig als Null oder 255
initialisiert ist, ergibt "c= !c" immer true (> 0). Als Beispiel sei C
Kaum.

> 0x0f, invertiert gibt das 0xf0 und beide Werte sind immer > 0. bool

Nachdem der "!"-Operator _zuerst_ seinen Operanden zu einem boolschen Wert
konvertiert (naja, sollte...), gibt !0x0f dasselbe wie !1, und das ist 0.
Damit wird in Deinem Beispiel "c= 0x0f; c= !c;" c _immer_ zu 0, was in C
gleichbedeutend mit "false" ist.

nicht zu initialsieren ist eine bĂśse Falle, die man unbedingt vermeiden
sollte.

Wobei es ein Teil der Sprachdefinition ist, daß _globale_ und als "static"
deklarierte Variablen vom Start-Code mit 0 oder einem explizit angegebenen
Wert initialisiert werden.
(Zur "main"-Funktion _lokale_ Variablen mĂźssen nicht initialisiert sein.)

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

Du schriebst am Mon, 09 Mar 2015 14:35:39 +0100:

Edzard Egberts wrote:
Ein Beispiel mit nicht initialisierten Bool-Werten.

bool a, b;
while (a!= b)
{
cout << "a!= b" << endl;
a= !a;
}

Im Debug-Modus finden Ăźbrigens bei manchen Systemen
Default-Initialisierungen statt (normalweise Null), also bitte als
Release testen.

Dein Beispiel ist sowieso unzutreffend, weil erstens die Variablen nicht
lokal sind (außer der Schnipsel wird in eine Funktion eingepflanzt) und
zweitens das kein C- sondern ein C++-ProgrammstĂźck ist.

--
--
(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, 09 Mar 2015 11:06:43 +0100:

Das liegt aber nicht an bool, sondern - wie ich schon schrieb - daran,
dass in C jeder Typ jedermanns Freund ist.

Ja, eben - C interpretiert bzw. konvertiert wild unter den Datentypen herum.

Nein, eben gerade nicht. C konvertiert Werte. Exemplarisch: ISO
9899:1999 §6.3.1.3p2: "Otherwise, if the new type is unsigned, the value
....
Noch schlimmer - da weiß man ja überhaupt nicht mehr, was am Ende der
Konversion 'rauskommt. Und wenn dann noch solche Exoten wie ...

> Repräsentation 0x8001 (...sign/magnitude-Darstellung vorausgesetzt) der

vorkommen können, dann ist jede Übersicht sowieso verloren.

ist das bei int versus float nicht der Fall - das _ist_ eine Ausnahme.

Nein, das ist der Regelfall. Um Repräsentationen zu konvertieren,

Nach Deinem obigen Zitat ja, aber - bei Konvertierungen zwischen "signed"-
und "unsigned"-Variablen habe ich bisher immer nur eine sture
Uminterpretation der Bitmuster gesehen.

schrammt man gerne mal am undefinierten Verhalten vorbei,
int i = *(int*) &floatVar;
ist z.B. nicht zulässig (§6.5p7).

Was heißt da "nicht zulässig"? Das ist nicht, was für eine Konversion
vorgesehen ist, aber es kĂśnnte ja aus irgendeinem Grund nĂśtig sein, das
_Bitmuster_ eines "float"-Wertes in einer "int"-Variablen zu trnasportieren
- und das geht halt mit solchen KrĂźcken. Es ginge natĂźrlich auch noch
anders, mit "union"s, z.B. Aber da müßte der Programmierer ja erstmal
sowas definieren.

)
{
bool b, c;
....
Hier war b "zufällig" anfangs 0, der gcc hat offenbar großzügig die
Deklarationen global angelegt.

Nein, gcc hat zufällig eine Speicherzelle oder ein Register mit dem Wert
0 erwischt.

Äh, ja, und was ist da der Unterschied zu "Variable war zufällig 0"?
Ich hielt(e) das fĂźr gleichwertig.

....
Nein. In Pascal - in _korrekt_ implementiertem Pascal - kann das _nicht_
....
In Pascal haben uninitialisierte lokale Variablen genauso wie in C
undefiniertes Verhalten.

Undefiniertes Verhalten ist _nicht_ identisch mit undefiniertem Wert!

ISO 10206:1990 6.4.2.1: "The initial state denoted by an enumerated-type
or a subrange-type shall be totally-undefined." (boolean ist ein
Enumerationstyp.)

Auf welche Programmiersprache bezieht sich dieses Zitat? Ich bin leider
kein ISO-Standard-Register.
Ungeachtet dessen ist das kein Widerspruch dazu, daß auch eine
uninitialisierte Variable keinen Wert außerhalb ihres zulässigen Bereichs
haben darf - wobei eine uninitialisierte Variable eigentlich als
Programm(ier)fehler behandelt werden müßte.

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
Sieghard Schicktanz wrote:
Du schriebst am Mon, 09 Mar 2015 11:06:43 +0100:
Das liegt aber nicht an bool, sondern - wie ich schon schrieb - daran,
dass in C jeder Typ jedermanns Freund ist.

Ja, eben - C interpretiert bzw. konvertiert wild unter den Datentypen herum.

Nein, eben gerade nicht. C konvertiert Werte. Exemplarisch: ISO
9899:1999 §6.3.1.3p2: "Otherwise, if the new type is unsigned, the value
...
Noch schlimmer - da weiß man ja überhaupt nicht mehr, was am Ende der
Konversion 'rauskommt. Und wenn dann noch solche Exoten wie ...

Repräsentation 0x8001 (...sign/magnitude-Darstellung vorausgesetzt) der

vorkommen können, dann ist jede Übersicht sowieso verloren.

Wen das Ăźberfordert (Konvertierung eines Wertes aus einer Darstellung in
den gleichen Wert in einer anderen Darstellung), der sollte vielleicht
die Finger von der Programmierung lassen.

ist das bei int versus float nicht der Fall - das _ist_ eine Ausnahme.

Nein, das ist der Regelfall. Um Repräsentationen zu konvertieren,

Nach Deinem obigen Zitat ja, aber - bei Konvertierungen zwischen "signed"-
und "unsigned"-Variablen habe ich bisher immer nur eine sture
Uminterpretation der Bitmuster gesehen.

Was daran liegt, dass heutzutage jeder nur noch two's-complement baut.
Und die Leute bauen deswegen nur noch two's complement, weil die
Konvertierungen da mit einer Uminterpretation der Bitmuster erledigt sind.

Aber C wĂźrde auch ohne gehen.

schrammt man gerne mal am undefinierten Verhalten vorbei,
int i = *(int*) &floatVar;
ist z.B. nicht zulässig (§6.5p7).

Was heißt da "nicht zulässig"? Das ist nicht, was für eine Konversion
vorgesehen ist, aber es kĂśnnte ja aus irgendeinem Grund nĂśtig sein, das
_Bitmuster_ eines "float"-Wertes in einer "int"-Variablen zu trnasportieren
- und das geht halt mit solchen KrĂźcken.

Nein, das geht nicht mit solchen KrĂźcken. Das wird gerne gemacht, aber
der Sprachstandard lässt das Verhalten dafßr undefiniert. Deswegen
explodiert das gerne mal, wenn jemand den Optimizer schlauer macht, und
äußert sich dann für den Normalentwickler als "Compiler-Optimizer-
Fehler", siehe Betreff.

Sicher geht das nur mit memcpy.

)
{
bool b, c;
...
Hier war b "zufällig" anfangs 0, der gcc hat offenbar großzügig die
Deklarationen global angelegt.

Nein, gcc hat zufällig eine Speicherzelle oder ein Register mit dem Wert
0 erwischt.

Äh, ja, und was ist da der Unterschied zu "Variable war zufällig 0"?

Das ist der Unterschied zu "hat die Deklarationen global angelegt", was
definitiv nicht der Fall ist.

Nein. In Pascal - in _korrekt_ implementiertem Pascal - kann das _nicht_
...
In Pascal haben uninitialisierte lokale Variablen genauso wie in C
undefiniertes Verhalten.

Undefiniertes Verhalten ist _nicht_ identisch mit undefiniertem Wert!

Stimmt, undefiniertes Verhalten darf auch Verhalten sein, das nicht nur
mit einem undefinierten Wert erklärbar ist. Zum Beispiel ein bool, der
sich weder wie true, noch wie false benimmt.

ISO 10206:1990 6.4.2.1: "The initial state denoted by an enumerated-type
or a subrange-type shall be totally-undefined." (boolean ist ein
Enumerationstyp.)

Auf welche Programmiersprache bezieht sich dieses Zitat? Ich bin leider
kein ISO-Standard-Register.

Du hast von Pascal geredet, also hab ich in den Standard fĂźr Pascal
geschaut ("Extended Pascal ISO 10206:1990"). Fand ich jetzt nicht so
weit hergeholt...

Ungeachtet dessen ist das kein Widerspruch dazu, daß auch eine
uninitialisierte Variable keinen Wert außerhalb ihres zulässigen Bereichs
haben darf - wobei eine uninitialisierte Variable eigentlich als
Programm(ier)fehler behandelt werden müßte.

Ist es auch. Aber keiner, den der Compiler erkennen muss.

Du hast behauptet, sowas ("uninitialisierte bool-Variable kann auch
einen Wert haben, der weder true noch false ist") kĂśnne in Pascal nicht
passieren. Ich meine: C und Pascal unterscheiden sich da Ăźberhaupt nicht.

Der Unterschied besteht zu Sprachen wie Java, JavaScript oder Perl, die
jede Variable bei Erzeugung auf einen wohldefinierten Wert setzen.


Stefan
 
Heinz Saathoff wrote:
Edzard Egberts schrieb:
Sieghard Schicktanz wrote:
int main (int argc, char * argv [])
{
bool b, c;
int i, k;

b= !c;

Das ist undefiniertes Verhalten, da c nicht initialisiert ist. Eine

Hier war b "zufällig" anfangs 0

Das ist aber ein großer Zufall, nämlich 1:254. bool wird intern ja
meistens in ein Byte gepackt, nicht in ein Bit und der Operator '!' ist
bei bool meistens als bitweise Invertierung der gesamten Variablen
implementiert.

Welcher Compiler macht denn sowas? Das ist ja eine fehlerhafe
Umsetzung des Operators !

Wir redeten von bool.

Datenpunkt: gcc-4.5.1 für i386 generiert für die Negation eines bools
eine Invertierung des untersten Bits:
xorl $1, %eax
gcc-4.8.3 für ARM ebenfalls:
eor r0, r0, #1
Testcode: 'bool nn(bool v) { return !v; }'.

Was würdest Du hier erwarten:
int i;
for(i=0; i<256; ++i) {
printf("%d\n", !i);

Das ist int. Völlig andere Baustelle.


Stefan
 
Hallo Stefan,

Du schriebst am Mon, 09 Mar 2015 23:40:54 +0100:

Nein, eben gerade nicht. C konvertiert Werte. Exemplarisch: ISO
9899:1999 §6.3.1.3p2: "Otherwise, if the new type is unsigned, the value
....
Wen das Ăźberfordert (Konvertierung eines Wertes aus einer Darstellung in
den gleichen Wert in einer anderen Darstellung), der sollte vielleicht
die Finger von der Programmierung lassen.

Mit solchen De- und Rereferenzierungskonstruktionen zur Typenentfernung und
Reinstitution wie in Deinem Beispiel mußt Du entweder ein enorm gutes
Gedächtnis oder eine gute Beschreibung haben, um selber nach ein paar
Jahren noch zu wissen, was da passiert. Ein Fremder, der da was damit
anfangen soll, steht erstmal "wie'n Ochs vor'm Berg".

"signed"- und "unsigned"-Variablen habe ich bisher immer nur eine sture
Uminterpretation der Bitmuster gesehen.

Was daran liegt, dass heutzutage jeder nur noch two's-complement baut.
Und die Leute bauen deswegen nur noch two's complement, weil die
Konvertierungen da mit einer Uminterpretation der Bitmuster erledigt sind.

Wenn man den zitierten Wortlaut ernst nimmt, dann geht das oft garnicht -
-1 läßt sich _nie_ als vorzeichenloser Wert darstellen ("is in the range of
the new type"). Da fehlt noch einiges an der reichlich verklausulierten
Beschreibung.

> Aber C wĂźrde auch ohne gehen.

Wobei immer noch fraglich ist, ob das die hauptsächlichen praktischen
Anwendungsfälle trifft.

schrammt man gerne mal am undefinierten Verhalten vorbei,
int i = *(int*) &floatVar;
....
Nein, das geht nicht mit solchen KrĂźcken. Das wird gerne gemacht, aber
der Sprachstandard lässt das Verhalten dafßr undefiniert. Deswegen

Hat er die MĂśglichkeit dazu? Das ginge nur, wenn die Zeiger typenspezifisch
unterschiedlich wären. MÜglich wäre das, "float"s kÜnnten ja z.B. Co-
Prozessor-resident gehalten werden und deren Zeiger auf einen Platz im Co-
Prozessor verweisen...
....
> Sicher geht das nur mit memcpy.

Nichtmal unbedingt damit, wenn's so extrem wird wie oben angedacht.
Muß nicht bei einer "union" sichergestellt sein, daß die Varianten alle
denselben Speicherplatz belegen?

Hier war b "zufällig" anfangs 0, der gcc hat offenbar großzügig die
Deklarationen global angelegt.
....
Äh, ja, und was ist da der Unterschied zu "Variable war zufällig 0"?

Das ist der Unterschied zu "hat die Deklarationen global angelegt", was
definitiv nicht der Fall ist.

Das hast Du aber nicht so gesagt. Das _kĂśnnte_ so sein, aber es ist
definitiv hier "etwas" initialisiert worden, was sich auf den Wert der
Variablen ausgewirkt hat, weil das Verhalten reproduzierbar war. Ob da der
Compiler einfach auch den Stack mal vorsichtshalber gelĂśscht hat oder
vielleicht doch die "main"-lokalen Variablen "globalisiert" müßte man
nachschauen.

....
Ungeachtet dessen ist das kein Widerspruch dazu, daß auch eine
uninitialisierte Variable keinen Wert außerhalb ihres zulässigen
Bereichs haben darf - wobei eine uninitialisierte Variable eigentlich
als Programm(ier)fehler behandelt werden müßte.

Ist es auch. Aber keiner, den der Compiler erkennen muss.

Nicht bei C, ja.

Du hast behauptet, sowas ("uninitialisierte bool-Variable kann auch
einen Wert haben, der weder true noch false ist") kĂśnne in Pascal nicht
passieren. Ich meine: C und Pascal unterscheiden sich da Ăźberhaupt nicht.

Die Ăźblichen Implementierungen nicht, das stimmt. C ist da zwar erheblich
weitergehend reglementiert als Pascal, dafĂźr ist die Reglementierung weniger
strikt. FĂźr Pascal gibt es zwar ein paar Standards, aber kaum eine
Implementierung, von den wenigen, die es gibt, hält sich daran.

--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
 
On 09.03.2015 22:54, Axel Berger wrote:
Heinz Saathoff wrote on Mon, 15-03-09 13:38:
Alles andere als 1 0 0 0 ... wäre falsch.

Sicher? Ich kenne NOT nur als bitweise Operation.

C kennt beides:
~ ist bitweise Invertierung
! ist logische Invertierung

--
Reinhardt
 
Stefan Reuther wrote:

Heinz Saathoff wrote:
Edzard Egberts schrieb:
Sieghard Schicktanz wrote:
int main (int argc, char * argv [])
{
bool b, c;
int i, k;

b= !c;

Das ist undefiniertes Verhalten, da c nicht initialisiert ist. Eine

Hier war b "zufällig" anfangs 0

Das ist aber ein großer Zufall, nämlich 1:254. bool wird intern ja
meistens in ein Byte gepackt, nicht in ein Bit und der Operator '!' ist
bei bool meistens als bitweise Invertierung der gesamten Variablen
implementiert.

Welcher Compiler macht denn sowas? Das ist ja eine fehlerhafe
Umsetzung des Operators !

Wir redeten von bool.

Datenpunkt: gcc-4.5.1 fĂźr i386 generiert fĂźr die Negation eines bools
eine Invertierung des untersten Bits:
xorl $1, %eax
gcc-4.8.3 fĂźr ARM ebenfalls:
eor r0, r0, #1
Testcode: 'bool nn(bool v) { return !v; }'.

Er nimmt hier an, dass eine ordentliche bool ankommt (also 0 oder 1). Dann
ist die Invertierung von bit 0 vollkommen richtig.

Was wĂźrdest Du hier erwarten:
int i;
for(i=0; i<256; ++i) {
printf("%d\n", !i);

Das ist int. VĂśllig andere Baustelle.


Stefan

Ich habe gerade mal auf meinem System getested:

#include <stdio.h>
#include <stdbool.h>

int main()
{
_Bool a, b;
int ia;

ia = 123;
a = ia;

printf("ia=%d a=%d a==b %d b=%d\n", ia, a, a==b, b);

return 0;
}

gcc version 4.7.1 20120723 [gcc-4_7-branch revision 189773] (SUSE Linux)

Er motzt (mit Recht) Ăźber nicht initialisiertes b:

main.c: In function 'main':
main.c:12:8: warning: 'b' is used uninitialized in this function [-
Wuninitialized]

output:
ia=123 a=1 a==b 0 b=4

Bei der Wertzuweisung an ein _Bool variable (a = ia) wird Code erzeugt, der
einen Wert 0 oder 1 erzeugt. Also da sorgt zumindest gcc fĂźr definierte
Verhältnisse

cmpl $0, 44(%esp)
setne %al
movb %al, 43(%esp)

--
Reinhardt
 
Edzard Egberts wrote:

Heinz Saathoff wrote:
Edzard Egberts schrieb:

Sieghard Schicktanz wrote:
#include <stdio.h
#include <stdbool.h

int main (int argc, char * argv [])
{
bool b, c;
int i, k;

b= !c;

Das ist undefiniertes Verhalten, da c nicht initialisiert ist. Eine

Hier war b "zufällig" anfangs 0

Das ist aber ein großer Zufall, nämlich 1:254. bool wird intern ja
meistens in ein Byte gepackt, nicht in ein Bit und der Operator '!' ist
bei bool meistens als bitweise Invertierung der gesamten Variablen
implementiert.

Welcher Compiler macht denn sowas? Das ist ja eine fehlerhafe
Umsetzung des Operators !

Bei dem Effekt bin ich mir sicher, bei meiner Erklärung nicht so. Kann
auch sein, dass der ! nur das Bit Null invertiert (halte ich sogar fĂźr
wahrscheinlicher als meine vorhergehende "komplett invertieren" Deutung,
weil das mit den Werten 0 / 1 besser hinkommt) und die Abfrage dann
wegen der anderen Bits durcheinander kommmt.

Das passt mit dem zusammen, was ich beim gcc sehe. Der dreht bit0 um. Aber
einer Wertzuweisung von einer int-expression sorgt er auch dafĂźr, dass nur
bit0 von 0 verschieden ist, schreibt also nicht den Wert der int, sondern 0
oder 1 je nachdem, ob die expr 0 oder nicht 0 ist.
So passt das dann. Mit reinem umdrehen von bit0 bleiben die Werte einer
_Bool Variablen im erlaubten Bereich.

Was wĂźrdest Du hier erwarten:

Ein Beispiel mit nicht initialisierten Bool-Werten.

bool a, b;
while (a!= b)
{
cout << "a!= b" << endl;
a= !a;
}

Wenn man die Warnings aktiviert und beachtet, sollte einem auffallen, dass
da undefiniertes gemacht wird.
Bei sowas ist der Compiler frei aus Garbage auch wieder Garbage (GIGO) zu
machen.
Das mag bei anderen Nanny-Sprachen anders sein.

--
Reinhardt
 
Axel Berger schrieb:

Heinz Saathoff wrote on Mon, 15-03-09 13:38:
Alles andere als 1 0 0 0 ... wäre falsch.

Sicher? Ich kenne NOT nur als bitweise Operation.

Ja, sicher! Bitweise Negation ist die Tilde ~
Das ist equivalent zu XOR mit 0xff..., wobei die
Anzahl der ff von der Datentypgröße abhängig ist.
Der Vorteil der ~ ist, dass man sich um die
Größe nicht kümmern muß.


- Heinz
 
Stefan Reuther schrieb:

Welcher Compiler macht denn sowas? Das ist ja eine fehlerhafe
Umsetzung des Operators !

Wir redeten von bool.

Datenpunkt: gcc-4.5.1 für i386 generiert für die Negation eines bools
eine Invertierung des untersten Bits:
xorl $1, %eax
gcc-4.8.3 für ARM ebenfalls:
eor r0, r0, #1
Testcode: 'bool nn(bool v) { return !v; }'.

Hast recht, ich hab nicht genau genug hingeschaut. Bei bool darf der
Compiler davon ausgehen, dass nur ein gültiger Wert false/true
vorliegt.


- Heinz
 
On 08.03.2015 21:13, Sieghard Schicktanz wrote:

Ja, man hat solange am Programm rumgebastelt, bis es irgendwie lief.
Warum weiß man nicht.

Das ist inzwischen doch ein vielgepriesenes Standardverfahren, das sog.
"agile programming"...

So ein himmelschreiender Unsinn. Das hat mit agile programming rein gar
nichts zu tun. Du hast offensichtlich agile programming nicht
verstanden, wenn du es mit "Gefrickel" verwechselst.

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>
 
On 08.03.2015 00:47, Sieghard Schicktanz wrote:

Wofßr bräuchte man denn das? Statt "if (var == TRUE)" schreibt man "if
(var)" und statt "if (var == FALSE)" schreibt man "if (!var)".

Und was "schreibt man" fĂźr "res= var1 == var2;", wenn var1 und var2 keine
sicheren booleschen Werte sind, das Ergebnis aber einer sein soll?

Wie kommst du denn darauf das das Ergebnis von "var1 == var2" nicht ein
sicherer boolescher Wert ist? Laut C Standard kommt da immer ein Wert
raus, der als bool funktioniert.

Da bleibt dann nur so eine Hilfskonstruktion wie "res= !var1 == !var2;".
SchÜn und einsichtig ist anders. Und das ist nur einer der mÜglichen Fälle.

Habe ich in der Praxis noch nicht gesehen und ist auch unnĂśtig. Im
Ăźbrigen kann man natĂźrlich auch casten: (bool)(var1 == var2). Habe ich
aber auch noch nie gesehen.

Zeig doch mal ein vollständiges Beispiel, wo der von dir geschilderte
fehlde "boolesche Verlgiechsoperatur" tatsächlich ein Problem macht.

Gruß,
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>
 
Sieghard Schicktanz wrote:
Du schriebst am Mon, 09 Mar 2015 23:40:54 +0100:
Nein, eben gerade nicht. C konvertiert Werte. Exemplarisch: ISO
9899:1999 §6.3.1.3p2: "Otherwise, if the new type is unsigned, the value
...
Wen das Ăźberfordert (Konvertierung eines Wertes aus einer Darstellung in
den gleichen Wert in einer anderen Darstellung), der sollte vielleicht
die Finger von der Programmierung lassen.

Mit solchen De- und Rereferenzierungskonstruktionen zur Typenentfernung und
Reinstitution wie in Deinem Beispiel mußt Du entweder ein enorm gutes
Gedächtnis oder eine gute Beschreibung haben, um selber nach ein paar
Jahren noch zu wissen, was da passiert. Ein Fremder, der da was damit
anfangen soll, steht erstmal "wie'n Ochs vor'm Berg".

Unsinn. Ich muss nur wissen: wenn ich einen Wert habe, der in den neuen
Typ reinpasst, bleibt der erhalten. Wenn er nicht passt, wird bei
ganzzahligen Typen mod-2**n gerechnet, unabhängig von der Repräsen-
tation. (Nichts anderes drĂźckt der Standard in vielen Worten aus.)

schrammt man gerne mal am undefinierten Verhalten vorbei,
int i = *(int*) &floatVar;
...
Nein, das geht nicht mit solchen KrĂźcken. Das wird gerne gemacht, aber
der Sprachstandard lässt das Verhalten dafßr undefiniert. Deswegen

Hat er die MĂśglichkeit dazu? Das ginge nur, wenn die Zeiger typenspezifisch
unterschiedlich wären. MÜglich wäre das, "float"s kÜnnten ja z.B. Co-
Prozessor-resident gehalten werden und deren Zeiger auf einen Platz im Co-
Prozessor verweisen...

Der Compiler darf so tun, als ob die Zeiger typspezifisch wären, auch,
wenn sie es praktisch - als Bitmuster im Register - nicht sind. Er darf
also davon ausgehen, dass ein Zeiger vom Typ 'int*' niemals auf eine
Speicherstelle zeigt, die als 'float' initialisiert wurde. Und das wird
in obigem Schnipsel verletzt.

Sicher geht das nur mit memcpy.

Nichtmal unbedingt damit, wenn's so extrem wird wie oben angedacht.

Es gibt eine Ausnahme, die i.W. besagt, dass ein 'char*' auf alles
zeigen darf, und memcpy kopiert chars.

Muß nicht bei einer "union" sichergestellt sein, daß die Varianten alle
denselben Speicherplatz belegen?

Muss es, aber der Lesezugriff auf eine andere Variante als die, die
initialisiert wurde, ist halt undefiniert.

gcc macht hier den Schritt nach vorne und definiert das Verhalten fĂźr
unions. Das darf er tun. "Der Compiler definiert" ist eine mĂśgliche
(aber halt nicht verpflichtende) Instanz von "der Sprachstandard lässt
undefiniert".

Hier war b "zufällig" anfangs 0, der gcc hat offenbar großzügig die
Deklarationen global angelegt.
...
Äh, ja, und was ist da der Unterschied zu "Variable war zufällig 0"?

Das ist der Unterschied zu "hat die Deklarationen global angelegt", was
definitiv nicht der Fall ist.

Das hast Du aber nicht so gesagt. Das _kĂśnnte_ so sein, aber es ist
definitiv hier "etwas" initialisiert worden, was sich auf den Wert der
Variablen ausgewirkt hat, weil das Verhalten reproduzierbar war. Ob da der
Compiler einfach auch den Stack mal vorsichtshalber gelĂśscht hat oder
vielleicht doch die "main"-lokalen Variablen "globalisiert" müßte man
nachschauen.

Spekulier einfach nicht so viel rum, schau einfach nach, wenn du Ăźber
Sprachstandards referieren willst.

Du hast behauptet, sowas ("uninitialisierte bool-Variable kann auch
einen Wert haben, der weder true noch false ist") kĂśnne in Pascal nicht
passieren. Ich meine: C und Pascal unterscheiden sich da Ăźberhaupt nicht.

Die Ăźblichen Implementierungen nicht, das stimmt. C ist da zwar erheblich
weitergehend reglementiert als Pascal, dafĂźr ist die Reglementierung weniger
strikt. FĂźr Pascal gibt es zwar ein paar Standards, aber kaum eine
Implementierung, von den wenigen, die es gibt, hält sich daran.

Du redetest von "_korrekt_ implementiertem Pascal". Was korrekt
implementiert ist, legt der Standard fest. Und der sagt: eine
uninitialisierte Variable in Pascal benimmt sich genauso wie eine
uninitialisierte Variable in C. Schau einfach nach, wenn du Ăźber
Sprachstandards referieren willst.


Stefan
 
On 10.03.2015 11:31, Stefan Reuther wrote:

Unsinn. Ich muss nur wissen: wenn ich einen Wert habe, der in den neuen
Typ reinpasst, bleibt der erhalten. Wenn er nicht passt, wird bei
ganzzahligen Typen mod-2**n gerechnet, unabhängig von der Repräsen-
tation. (Nichts anderes drĂźckt der Standard in vielen Worten aus.)

Falsch!

Der Standard definiert solche Konversionen nur fĂźr unsignierte
Datentypen. Bei signierten Datentypen ist der overflow explizit
undefiniert und da führt regelmäßig zu Problemen mit Leuten, die
Overflow-PrĂźfung machen wollen:

static int a;
void moo(int x) {
assert(a + x >= a);
...
}

Denn da darf der Compiler dann (vĂśllig zu Recht) das assert einfach
wegoptimieren.

Auf vielen gängigen Architekturen mit gängigen Compilern ist das zwar
so, dass das Verhalten wohldefiniert ist, das ist dann aber kein
portables C mehr.

Es gibt eine Ausnahme, die i.W. besagt, dass ein 'char*' auf alles
zeigen darf, und memcpy kopiert chars.

memcpy kopiert natĂźrlich keine chars:

void *memcpy(void *dest, const void *src, size_t n);

Sondern hat im Prototyp void*, der nicht zu den von dir o.g.
aliasing-Problemen fĂźhrt.

Muß nicht bei einer "union" sichergestellt sein, daß die Varianten alle
denselben Speicherplatz belegen?

Muss es, aber der Lesezugriff auf eine andere Variante als die, die
initialisiert wurde, ist halt undefiniert.

Fast richtig. Das war genau so wie du schreibst, aber ist in C11 jetzt
geändert worden. War ohnehin eine schrottige Definition im Standard und
wurde von quasi allen Compilern so interpretiert, wie C11 es jetzt
vorschreibt.

gcc macht hier den Schritt nach vorne und definiert das Verhalten fĂźr
unions. Das darf er tun. "Der Compiler definiert" ist eine mĂśgliche
(aber halt nicht verpflichtende) Instanz von "der Sprachstandard lässt
undefiniert".

Das ist der Unterschied zwischen "implementation defined" und "undefined".

Gruß,
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