Forum: Mikrocontroller und Digitale Elektronik ARM-GCC versteht den Witz nicht.


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

aus Langeweile habe ich mal einen gerade kursierenden Witz 
ausprobiert/implementiert:
1
volatile int a = "100" + 2 == "0"
(das Ganze in einer ansonsten nackten main() und mit dem Debugger das 
Ergebnis auf einem STM32F103C8RB angeschaut.)

ARM-GCC 5.4.1  -O3: a ist false
ARM-GCC 5.4.1  -Os: a ist true

Aber nicht nur das. Es wird für den Ausdruck auf der rechten Seite 
tatsächlich Code generiert:
1
(32)      volatile int isInterleaved = "100"+2 == "0";
2
08000282  ldr  r3, [pc, #16]  ; (0x8000294 <main+20>)
3
08000284  ldr  r2, [pc, #16]  ; (0x8000298 <main+24>)
4
08000286  subs  r2, r3, r2
5
08000288  negs  r3, r2
6
0800028A  adcs  r3, r2
7
0800028C  str  r3, [sp, #4]

Das erzeugt zwei Fragen:
 a) Warum spart sich der Compiler das Schachteln der Zeichenketten in 
-O3? Ich kann durch das Schachteln keine Strafe auf die Geschwindigkeit 
erkennen.
 b) Warum kann der Compiler den konstanten Ausdruck auf der rechten 
Seite nicht auswerten und wegoptimieren? Zumindest bei -Os hat er doch 
erkannt, dass die Differenz immer 4 ist?

: Bearbeitet durch User
Beitrag #6748676 wurde von einem Moderator gelöscht.
von mh (Gast)


Lesenswert?

Walter T. schrieb:
> Das erzeugt zwei Fragen:
>  a) Warum spart sich der Compiler das Schachteln der Zeichenketten in
> -O3? Ich kann durch das Schachteln keine Strafe auf die Geschwindigkeit
> erkennen.
>  b) Warum kann der Compiler den konstanten Ausdruck auf der rechten
> Seite nicht auswerten und wegoptimieren? Zumindest bei -Os hat er doch
> erkannt, dass die Differenz immer 4 ist?

Die für mich relevante Frage samt Antwort fehlt. Was erwartest du als 
Ergebnis?

von Walter T. (nicolas)


Lesenswert?

mh schrieb:
> Was erwartest du als
> Ergebnis?

"Implementation defined behaviour"

von Klaus W. (mfgkw)


Lesenswert?

Walter T. schrieb:
> ARM-GCC 5.4.1  -O3: a ist false
> ARM-GCC 5.4.1  -Os: a ist true

Mein gcc ist meistens auch humorlos.
Mit -Wall kommentiert er es als das, was es ist:
a.c:8:33: warning: comparison with string literal results in unspecified 
behavior [-Waddress]

Insofern hat er recht, wenn mal das eine und mal das andre rauskommt.

von Andreas M. (amesser)


Lesenswert?

Wie kommst Du darauf, das die Differenz "4" ist? Du addierst auf einen 
(const char) Pointer "100" den Wert 2 und vergleichst diesen neuen 
Pointer mit einem weiteren Pointer.

Bei "-Os" macht der Compiler vermutlich einen String Merge von "100" und 
"0": Es reicht "100" im Code zu hinterlegen, man kann "0" als Substring 
darstellen.

von mh (Gast)


Lesenswert?

Walter T. schrieb:
> mh schrieb:
>> Was erwartest du als
>> Ergebnis?
>
> "Implementation defined behaviour"

Der gcc mit Wall sagt undefined. Warum sollte es auch implementation 
defined sein?

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
>> Was erwartest du als Ergebnis?

> "Implementation defined behaviour"

Bitte konkreter: was erwartest, und warum? Was wäre denn für dich in 
diesem Fall "defined behaviour" oder (wenn es keine solche Definition 
gibt) wie würdest du das Soll-Verhalten definieren wollen?

Meiner Meinung nach ist die Codezeile sinnloser Bullshit den keine Regel 
von C beschreibt.

von MaWin (Gast)


Lesenswert?

Walter T. schrieb:
> Hallo
> versteht den Witz nicht...

...dann solltest du nicht in C programmieren.
"Denn sie wissen nicht, was sie tun"

Beitrag #6748702 wurde von einem Moderator gelöscht.
von foobar (Gast)


Lesenswert?

> Das erzeugt zwei Fragen:
> a) Warum spart sich der Compiler das Schachteln der Zeichenketten in
> -O3? Ich kann durch das Schachteln keine Strafe auf die Geschwindigkeit
> erkennen.

Der String ist nicht mehr aligned und Zugriffe drauf evtl langsamer.

> b) Warum kann der Compiler den konstanten Ausdruck auf der rechten
> Seite nicht auswerten und wegoptimieren? Zumindest bei -Os hat er doch
> erkannt, dass die Differenz immer 4 ist?

Bei zwei unabhängigen Strings vergibt erst der Linker die Adressen.

von mh (Gast)


Lesenswert?

foobar schrieb:
> Bei zwei unabhängigen Strings vergibt erst der Linker die Adressen.
Die Strings sind nicht zwingend "unabhängig". Der Compiler/Linker darf 
die letzte das Ende von "100" als "0" benutzen. Das ist das unspecified 
Verhalten, dass hier schon genannt wurde. Wenn der Compiler/Linker das 
nicht macht, ist das Verhalten undefined, weil die beiden Pointer nicht 
in das selbe Objekt (Array-of-char) zeigen.

von Walter Tarpan (Gast) (Gast)


Lesenswert?

Andreas M. schrieb:
> Wie kommst Du darauf, das die Differenz "4"

Tippfehler. Das Listing hatte mich irritiert.

foobar schrieb:
> Der String ist nicht mehr aligned und Zugriffe drauf evtl langsamer.

Das klingt plausibel.

foobar schrieb:
> Bei zwei unabhängigen Strings vergibt erst der Linker die Adressen.

Das auf den ersten Blick nicht: Wenn der Compiler die Strings 
schachtelt, ist die Bedingung immer erfüllt, egal wie der Linker ihn 
schiebt. Wenn nicht, nie. Aber okay. Der Compiler hat in der abstrakten 
Maschine nichts mit den Adressen zu schaffen.

Ob LTO etwas an der Situation ändert?

von Walter T. (nicolas)


Lesenswert?

Stefan ⛄ F. schrieb:
> Meiner Meinung nach ist die Codezeile sinnloser Bullshit den keine Regel
> von C beschreibt.

Ich kenne keine Regel, die diese Zeile verbietet. Aber ich bin nur 
Hobbyist und lerne gern dazu.


mh schrieb:
> Der gcc mit Wall sagt undefined.

Meiner sagt übrigens "unspecified behavior", also der schmale Grat 
zwischen implementation defined und undefined, auf dem ich gefühlt noch 
nie zuvor spaziert bin.


mh schrieb:
> Wenn der Compiler/Linker das
> nicht macht, ist das Verhalten undefined, weil die beiden Pointer nicht
> in das selbe Objekt (Array-of-char) zeigen.

Ich kenne keine Regel, die den Vergleich beliebiger Zeiger auf 
unterschiedliche Arrays verbietet.


Walter Tarpan (Gast) schrieb:
> Ob LTO etwas an der Situation ändert?

Die Frage fand ich dann doch noch interessant genug, den PC noch einmal 
zu starten. Bei LTO ergibt sich kein Unterschied. -O3 und -Os haben 
immer noch jeweils das zuvor beschriebene Verhalten in Bezug auf das 
jeweilige Ergebnis (true|false).

Aaber: Die rechte Seite wird jetzt komplett wegoptimiert, und jeweils 
der Wert als Immediate direkt geladen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Walter T. schrieb:
> Ich kenne keine Regel, die den Vergleich beliebiger Zeiger auf
> unterschiedliche Arrays verbietet.

Der C Standard kennt eine. Ein Vergleich zwischen Pointern auf 
verschiedene Arrays ist undefiniert. 6.5.8.5 ... "In all other cases, 
the behavior is undefined."

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

(prx) A. K. schrieb:
> Der C Standard kennt eine. Ein Vergleich zwischen Pointern auf
> verschiedene Arrays ist undefiniert.

Findest Du die Stelle? Ich finde das nur in MISRA & Co.

von mh (Gast)


Lesenswert?

Walter T. schrieb:
> mh schrieb:
>> Der gcc mit Wall sagt undefined.
>
> Meiner sagt übrigens "unspecified behavior", also der schmale Grat
> zwischen implementation defined und undefined, auf dem ich gefühlt noch
> nie zuvor spaziert bin.

Ja er sagt unspecified, ich habe gelesen, was ich erwartet habe. Und 
implementation defined ist nochmal was anderes. Es ist unspecified, weil 
der Compiler die Strings zusammenlegen darf, wenn es möglich ist. Er 
muss er muss aber nicht dokumentieren, ob oder wann er es macht. Wenn er 
es dokumentieren müsste, wäre es implementation defined. Undefined wird 
es, weil Pointer auf unterschiedliche Objekte verglichen werden, wenn er 
sie nicht zusammen legt.
Da du dir aber nicht sicher sein kannst welches Verhalten gerade 
zutrifft, ist es effektiv immer undefined.

Walter T. schrieb:
> mh schrieb:
>> Wenn der Compiler/Linker das
>> nicht macht, ist das Verhalten undefined, weil die beiden Pointer nicht
>> in das selbe Objekt (Array-of-char) zeigen.
> Ich kenne keine Regel, die den Vergleich beliebiger Zeiger auf
> unterschiedliche Arrays verbietet.
1
6.5.8 Relational operators
2
...
3
5) When two pointers are compared, the result depends on the relative locations in the address space
4
of the objects pointed to. If two pointers to object types both point to the same object, or both point
5
one past the last element of the same array object, they compare equal. If the objects pointed to are
6
members of the same aggregate object, pointers to structure members declared later compare greater
7
than pointers to members declared earlier in the structure, and pointers to array elements with larger
8
subscript values compare greater than pointers to elements of the same array with lower subscript
9
values. All pointers to members of the same union object compare equal. If the expression P points
10
to an element of an array object and the expression Q points to the last element of the same array
11
object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.

von Sebastian (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Der C Standard kennt eine. Ein Vergleich zwischen Pointern auf
> verschiedene Arrays ist undefiniert. 6.5.8.5 ... "In all other cases,
> the behavior is undefined."

Wirklich? Pointergleichheit ist undefiniert? Oder nur kleiner/grösser?

LG, Sebastian

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Ich kenne keine Regel, die diese Zeile verbietet.

Die Zeile ist nicht verboten. Aber sie enthält einige Konstrukte, die 
vielleicht anders sind als Du erwartest und die deshalb vielleicht 
andere Ergebnisse liefern als Du erwartest.

Darum die Frage, was Du erwartest.

Dass verschiedene Dinge rauskommen, liegt daran, dass der Compiler frei 
ist, das zu implementieren, wie er will.

Also ganz ehrlich, verstehst Du, wann genau true rauskommt und wann 
genau nicht?

von Walter T. (nicolas)


Lesenswert?

@ A.K.: Da gab es wohl eine Überschneidung. Danke fürs heraussuchen.

@mh: Ebenfalls danke fürs heraussuchen und hineinkopieren.

Jetzt wird es interessant.

Ich habe die letzte Zeile tatsächlich so gelesen, dass sie sich auf den 
Vergleich P == Q+1 bezieht.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Sebastian schrieb:
> Wirklich? Pointergleichheit ist undefiniert? Oder nur kleiner/grösser?

hier letzteres

von (prx) A. K. (prx)


Lesenswert?

Sebastian schrieb:
> Wirklich? Pointergleichheit ist undefiniert? Oder nur kleiner/grösser?

6.5.9.3: "The == (equal to) and != (not equal to) operators are 
analogous to the relational operators except for their lower 
precedence."

von Walter T. (nicolas)


Lesenswert?

A. S. schrieb:
> Darum die Frage, was Du erwartest.

Und die Frage noch zu klären: Ich erwartete hier, etwas Neues über die 
Arbeitsweise des Optimierers zu lernen.

von Sebastian (Gast)


Lesenswert?

(prx) A. K. schrieb:
> 6.5.8.5 ... "In all other cases, the behavior is undefined."

Das gilt für relationale Operatoren. Pointergleichheit wird in 6.5.9, 
inbesonders 6.5.9.6 spezifiziert. Zwei Pointer auf unterschiedliche 
Speicherbereiche sind ungleich, nicht undefiniert.

LG, Sebastian

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Ich habe die letzte Zeile tatsächlich so gelesen, dass sie sich auf den
> Vergleich P == Q+1 bezieht.

Da geht es nur darum, dass man quasi das es quasi genau ein Element 
gibt, dass sicher größer als das letzte Element ist.

Hat hier aber keine Bedeutung.

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Und die Frage noch zu klären: Ich erwartete hier, etwas Neues über die
> Arbeitsweise des Optimierers zu lernen.

In welcher Hinsicht?

von (prx) A. K. (prx)


Lesenswert?

Walter T. schrieb:
> Ich habe die letzte Zeile tatsächlich so gelesen, dass sie sich auf den
> Vergleich P == Q+1 bezieht.

Damit wird sehr verbreiteter Code wie
   ... array[N];
   for (p = &array[0], q = &array[N]; p < q; ++p)
zulässig, obwohl q eigentlich ins Nirvana zeigt. Es geht dabei nicht um 
Pointer auf verschiedene Objekte.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

mh schrieb:
> Da du dir aber nicht sicher sein kannst welches Verhalten gerade
> zutrifft, ist es effektiv immer undefined.

Naja, für mich gibt es zwischen "undefined" und "unspecified" einen 
heftigen Unterschied: Bei "undefined" macht der Compiler ein lautes 
"Ätsch, jetzt bringe ich Dir alle anderen Sachen auch noch 
durcheinander! Ich darf das!", bei "unspecified" steht in einer Variable 
ein falscher/unerwarteter Wert.

Aber ich bin jetzt etwas irritiert:
1
int a, b, *ap, *bp;
2
ap = &a, bp = &b; 
3
int c = *ap == *bp;
Definiert oder nicht definiert?

Wenn ich mir den Absatz noch einmal in Ruhe durchlesen, würde ich 
ersteres sagen. Und c ist immer 0.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Sebastian schrieb:
>> 6.5.8.5 ... "In all other cases, the behavior is undefined."
>
> Das gilt für relationale Operatoren. Pointergleichheit wird in 6.5.9,
> inbesonders 6.5.9.6 spezifiziert. Zwei Pointer auf unterschiedliche
> Speicherbereiche sind ungleich, nicht undefiniert.

Da 6.5.9.3 Vergleiche auf Gleichheit auf relationale Vergleiche 
zurückführt, gelten folglich die Regeln aus 6.5.8 analog.

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Das erzeugt zwei Fragen:
>  a) Warum spart sich der Compiler das Schachteln der Zeichenketten in
> -O3? Ich kann durch das Schachteln keine Strafe auf die Geschwindigkeit
> erkennen.
Wozu? Die Strings fallen doch weg, er braucht sie nicht anlegen. Der 
restliche Code kann sie ja eh nicht "fassen".
>  b) Warum kann der Compiler den konstanten Ausdruck auf der rechten
> Seite nicht auswerten und wegoptimieren? Zumindest bei -Os hat er doch
> erkannt, dass die Differenz immer 4 ist?
Ist der erstellte Code in beiden gleich? Ggf. weil der Linker ja erst 
die Adressen liefert ;-)

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Aber ich bin jetzt etwas irritiert:
> int a, b, *ap, *bp;
> ap = &a, bp = &b;
> int c = *ap == *bp;
> Definiert oder nicht definiert?
>
> Wenn ich mir den Absatz noch einmal in Ruhe durchlesen, würde ich
> ersteres sagen. Und c ist immer 0.
Definiert, klar. Warum nicht. Aber warum 0? was in a oder b steht ist 
doch völlig unbekannt. Die können gleich sein, müssen aber nicht.

von Walter T. (nicolas)


Lesenswert?

(prx) A. K. schrieb:
> Es geht dabei nicht um
> Pointer auf verschiedene Objekte.

Genau. Also würde ich den Satz "In all other cases, the behavior is 
undefined." explizit auf den Vergleich zweier Zeiger auf das gleiche 
Array beziehen. Das steht deshalb da, weil die Regel für Zeiger hier 
etwas aufgeweicht sind, weil ein Element über das Array hinaus gezeigt 
werden darf.

Oben: Tippfehler. Gemeint ist natürlich
1
int a, b, *ap, *bp;
2
ap = &a, bp = &b; 
3
int c = ap == bp;

Bin zwar nicht so schnippisch wie ein Compiler, werde aber dafür 
schneller müde.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Walter T. schrieb:
> A. S. schrieb:
>> Darum die Frage, was Du erwartest.
>
> Und die Frage noch zu klären: Ich erwartete hier, etwas Neues über die
> Arbeitsweise des Optimierers zu lernen.

Daß der nach dem GIGO Prinzip arbeitet? Oder was?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sebastian schrieb:
> Zwei Pointer auf unterschiedliche Speicherbereiche sind ungleich, nicht
> undefiniert.

Es ist aber nicht sicher, ob es sich um unterschiedliche 
Speicherbereiche handelt oder nicht. Diese Auswahl ist dem Compiler 
freigestellt.

6.4.5 (in meinem Draft, den ich gerade habe ;), steht aber schon lange 
so drin)

String literals

"It is unspecified whether these arrays are distinct provided their 
elements have the appropriate values. If the program attempts to modify 
such an array, the behavior is undefined."

Damit ist das Verhalten hier "unspecified", und es ist völlig plausibel, 
dass abhängig von der gewählten Optimierung unterschiedliche Ergebnisse 
produziert werden.

von (prx) A. K. (prx)


Lesenswert?

Dieses Loch des C Standards C wurde in C++ explizit gestopft. 5.10: 
"Pointers of the same type (after pointer conversions) can be compared 
for equality. Two pointers of the same type compare equal if and only if 
they are both null, both point to the same function, or both represent 
the same address (3.9.2)"

Für C könnte man auch sagen, dass das Verhalten schon deshalb 
undefiniert ist, weil der Standard es weder als klar definiert noch als 
klar undefiniert definiert. ;-)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Dieses Loch des C Standards C wurde in C++ explizit gestopft.

An der Stelle nicht wirklich: die Frage ist ja, ob sie im obigen 
Beispiel auch tatsächlich auf die gleiche Adresse zeigen oder nicht. Es 
würde mich wundern, wenn der C++-Standard an dieser Stelle expliziter 
wäre und entweder das Zusammenlegen oder das Verteilen der beiden den 
Strings zugrundeliegenden Arrays vorschriebe.

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> Oben: Tippfehler. Gemeint ist natürlichint a, b, *ap, *bp;
> ap = &a, bp = &b;
> int c = ap == bp;

a und b sind doch in jedem Fall unterschiedliche Adressen. Also ja, 0, 
ungleich.

Beim String-Beispiel ist es ja eher so, dass Du zwei "zufällige" 
Adressen hast, die je nach Laune gleich oder ungleich sein können.

Da strings auch nicht unterschiedlich sein können, wenn sie den gleichen 
Anfang haben, ist das auch kein praktisches Problem.

Entweder sind strings (die Adressen) gleich, dann ist auch der Text 
gleich. Oder sie sind es nicht, dann ist der Text beliebig. Meist 
unterschiedlich, kann aber trotzdem gleich sein.

von (prx) A. K. (prx)


Lesenswert?

Zwischen den Zeilen gelesen ist ein Vergleich auf Gleichheit auch in C 
definiert: "Two pointers compare equal if and only if [...] one is a 
pointer to one past the end of one array object and the other is a 
pointer to the start of a different array object that happens to 
immediately follow the first array object in the address space."

von Oliver S. (oliverso)


Lesenswert?

Walter T. schrieb:
> Genau. Also würde ich den Satz "In all other cases, the behavior is
> undefined." explizit auf den Vergleich zweier Zeiger auf das gleiche
> Array beziehen.

Nein. Der Text ist da sehr eindeutig.

Da steht eine Aufzählung aller zugelassenen Vergleiche, und an deren 
Ende, daß alle anderen Fälle undefined sind. Da gibts wenig dran zu 
deuteln.

Oliver

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Zwischen den Zeilen gelesen ist ein Vergleich auf Gleichheit auch in C
> definiert

Ja.

Die einzige Unsicherheit ist halt, ob es sich um die gleichen 
Array-Objekte handelt oder nicht.

von Walter T. (nicolas)


Lesenswert?

Oliver S. schrieb:
> Da steht eine Aufzählung aller zugelassenen Vergleiche, und an deren
> Ende, daß alle anderen Fälle undefined sind. Da gibts wenig dran zu
> deuteln.

Dann wäre allerdings der Vergleich a == NULL auch undefined.

von (prx) A. K. (prx)


Lesenswert?

Jörg W. schrieb:
> (prx) A. K. schrieb:
>> Dieses Loch des C Standards C wurde in C++ explizit gestopft.
>
> An der Stelle nicht wirklich: die Frage ist ja, ob sie im obigen
> Beispiel auch tatsächlich auf die gleiche Adresse zeigen oder nicht.

Mit dem Loch meinte ich die klare Festlegung im Standard, ob Vergleiche 
auf Identität von Pointern auf verschiedene Objekte zulässig sind. Ich 
würde nun sagen, dass sie es auch in C sind. Nicht festgelegt ist damit 
aber, das Vergleiche auf verschiedene Objekte notwendigerweise auf 
"ungleich" entscheiden.

von A. S. (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Für C könnte man auch sagen, dass das Verhalten schon deshalb
> undefiniert ist, weil der Standard es weder als klar definiert noch als
> klar undefiniert definiert. ;-)

Das gilt aber nur, wenn Du

(prx) A. K. schrieb:
> 6.5.9.3: "The == (equal to) and != (not equal to) operators are
> analogous to the relational operators except for their lower
> precedence."

auf eine Eigenschaft beziehst, die nicht zwingend mitgemeint sein muss.

Es gibt ja so ein analogon bei % und / mit negativen Zahlen bei int. 
Egal wie mans macht, am Ende muss es Konsistent sein. Und bei > bzw. < 
auch: Egal was raus kommt, am Ende muss es (bei ungleichen Pointern) > 
oder < sein, um ein == zu erkennen. Und das ist so offensichtlich, dass 
es keiner expliziten Erklärung bedarf, die Hälfte aller 
Pointer-Vergleiche wäre sonst sinnlos.

von Gerald K. (geku)


Lesenswert?

Das Problem könnte sein, dass für die Zeichenkette "100" zur 
Kompilierzeit noch keine Adresse feststeht, da diese erst beim Linken 
gebildet wird. Daher muss der Algorithmus diese Adresse zur Laufzeit 
berechnen. Damit muss auch der restliche Ausdruck zur Laufzeit berechnet 
werden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gerald K. schrieb:
> Das Problem könnte sein, dass für die Zeichenkette "100" zur
> Kompilierzeit noch keine Adresse feststeht, da diese erst beim Linken
> gebildet wird.

Je nachdem eben. Es ist dem Compiler völlig freigestellt, ob er das 
bereits beim Compilieren zusammenwürfelt (möglich ist es ja) oder nicht.

Daher "unspecified". Es ist nicht "undefined", d.h. der Compiler kann 
sich eine von beiden Varianten aussuchen (die Zeiger sind gleich oder 
nicht), aber das Ergebnis darf nicht etwas ganz was anderes tun.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

z.B. nethack spielen ;-)

https://feross.org/gcc-ownage/

von Jemand (Gast)


Lesenswert?

A. S. schrieb:
> Definiert, klar. Warum nicht.

`a` und `b` enthalten indeterminate values, dürfen also eine /trap 
representation/ enthalten, der Zugriff darauf wäre undefined behavior.

von Gerald K. (geku)


Lesenswert?

Jörg W. schrieb:
> Es ist dem Compiler völlig freigestellt, ob er das bereits beim
> Compilieren zusammenwürfelt (möglich ist es ja) oder nicht.

Der Compiler kann keine absoluten Adressen bilden. Die Adressen stehen 
erst zur Lauzeit fest.
Werden zwei Instanzen des Programms gestartet, dann hat die Zeichenkette 
"100" zwei verschiedene Adressen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jemand schrieb:
> a und b enthalten /indeterminate values/

Ist aber für das Beispiel egal, da nur deren Adressen via & ermittelt 
werden. Die Adressen haben (nach dem Linken) einen wohl definierten 
Wert. Auf die Inhalte wird nicht zugegriffen.

Hat mit dem originalen Problem aber gar nichts zu tun.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gerald K. schrieb:
> Der Compiler kann keine absoluten Adressen bilden.

Muss er auch nicht.

Trotzdem darf er "0\0" auf das Ende von "100\0" zeigen lassen, aber er 
muss nicht. Um nicht mehr und nicht weniger geht es im initialen 
Beispiel.

Es ist nicht der Linker, der "100\0" und "0\0" miteinander vereint.

von Sebastian (Gast)


Lesenswert?

A. S. schrieb:
> Egal was raus kommt, am Ende muss es (bei ungleichen Pointern) > oder <
> sein

Ja, aber welches von beiden kann undefined sein. Und bei zwei Zeigern 
auf unterschiedliche Variablen ist eben Ungleichheit garantiert, aber 
nicht welcher Zeiger der Grössere ist.

Die Operatoren == und != sind eben nicht relational operators nach 6.5.8 
(das sind <, >, <= und >=) sondern equality operators nach 6.5.9.

LG, Sebastian

von Oliver S. (oliverso)


Lesenswert?

Walter T. schrieb:
> Oliver S. schrieb:
>> Da steht eine Aufzählung aller zugelassenen Vergleiche, und an deren
>> Ende, daß alle anderen Fälle undefined sind. Da gibts wenig dran zu
>> deuteln.
>
> Dann wäre allerdings der Vergleich a == NULL auch undefined.

Nein. Der Abschnitt behandelt ausdrücklich den Vergleich von zwei 
Pointern, nicht den Test von einem Pointer auf Null.

Oliver

von Sebastian (Gast)


Lesenswert?

Oliver S. schrieb:
> Der Abschnitt behandelt ausdrücklich den Vergleich von zwei Pointern,

Vergleich mit relational operators. Der Abschnitt behandelt nicht ==.

LG, Sebastian

von Jemand (Gast)


Lesenswert?

Jörg W. schrieb:
> Ist aber für das Beispiel egal, da nur deren Adressen via & ermittelt
> werden. Die Adressen haben (nach dem Linken) einen wohl definierten
> Wert. Auf die Inhalte wird nicht zugegriffen.

Zitierter Beitrag bezieht sich noch auf das Beispiel vor der Korrektur.

von Gerald K. (geku)


Lesenswert?

Jörg W. schrieb:
> Trotzdem darf er "0\0" auf das Ende von "100\0" zeigen lassen, aber er
> muss nicht. Um nicht mehr und nicht weniger geht es im initialen
> Beispiel.

 **Einverstanden**

"0\0" ist ein Teil von "100\0".  Es könnte die gleiche Zeichenkette 
"100\0" verwendet werden.
Für "0\0" ist die Adresse um zwei größer, falls die Optimierung dies so 
umsetzt. Der absolute Wert kürzt sich heraus.

Beitrag #6748957 wurde von einem Moderator gelöscht.
von A. S. (Gast)


Lesenswert?

Jemand schrieb:
> `a` und `b` enthalten indeterminate values, dürfen also eine /trap
> representation/ enthalten, der Zugriff darauf wäre undefined behavior.

Ich kenne mich da nicht aus. Ich hätte gedacht, es wäre bei int (@C11) 
ein "unspecified value".

1
3.19.2 indeterminate value
2
either an unspecified value or a trap representation
3
3.19.3 unspecified value
4
valid value of the relevant type where this International Standard imposes no
5
requirements on which value is chosen in any instance
6
2 NOTE An unspecified value cannot be a trap representation.
7
3.19.4 trap representation
8
an object representation that need not represent a value of the object type

von Jemand (Gast)


Lesenswert?

A. S. schrieb:
> Ich kenne mich da nicht aus. Ich hätte gedacht, es wäre bei int (@C11)
> ein "unspecified value".

In 6.7.9 Initialization:
1
10 If an object that has automatic storage duration is not initialized explicitly, its value is
2
indeterminate. [...]

von Nop (Gast)


Lesenswert?

(prx) A. K. schrieb:

> Der C Standard kennt eine. Ein Vergleich zwischen Pointern auf
> verschiedene Arrays ist undefiniert. 6.5.8.5 ... "In all other cases,
> the behavior is undefined."

Wenn der zweite String nicht reingefaltet wird UND direkt nach dem 
ersten String liegt, wäre der zweite Pointer aus Sicht des ersten 
Strings so ein "q+1".

Wenn der Compiler nicht reinfaltet, kann er zur Compile-Zeit nicht 
wissen, wo die Adressen liegen werden, kann also nicht mit Sicherheit 
sagen, ob es noch q+1 sein wird oder nicht. Er darf aber q+1 annehmen, 
weil das Gegenteil undefined behaviour wäre, so daß er für den letzteren 
Fall keinen Code generieren muß.

von Al Fine (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Mit dem Loch meinte ich die klare Festlegung im Standard, ob Vergleiche
> auf Identität von Pointern auf verschiedene Objekte zulässig sind.

Gratuliere! Das erfordert schon eine große Menge an echter 
Abgezogenheit, wenn im Standard steht
[code]
Two pointers compare equal if ...  both are pointers to the same object 
...
[/code
dann noch zu denken, wenn das nicht der Fall ist, wäre nicht der 
Vergleich false, sondern das Verhalten undefiniert.
Echt, Gratuliere!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gerald K. schrieb:

> "0\0" ist ein Teil von "100\0".  Es könnte die gleiche Zeichenkette
> "100\0" verwendet werden.
> Für "0\0" ist die Adresse um zwei größer, falls die Optimierung dies so
> umsetzt. Der absolute Wert kürzt sich heraus.

Yep, genau darum dreht sich das initiale Beispiel. Es gibt 
Optimierungsstufen, bei denen der Compiler das genau so umsetzt (und 
daher "true" ermittelt), und es gibt welche, bei denen er das nicht 
umsetzt. Dann wird die Adresszuordnung dem Linker überlassen, wobei aber 
eigentlich bereits dem Compiler klar ist, dass es sich um zwei 
verschiedene Objekte im Speicher handelt, sodass er entweder selbst 
"false" einsetzen kann (optimiert) oder aber die Rechnung zur Laufzeit 
ausführen lässt (nicht optimiert).

Damit erzeugt zwar nichts davon undefined behaviour (um dessen 
potenzielle Folgen sich gerade in WG14 heiße Diskussionen ranken), aber 
es ist halt "unspecified".

von Gerald K. (geku)


Angehängte Dateien:

Lesenswert?

1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <inttypes.h>
5
6
int main(int argc, char* argv[])
7
{
8
        char *p1="100";
9
        char *p2="0";
10
11
        volatile int a = p1 + 2 == p2;
12
13
        printf("p1=%p, p2=%p\r\n",p1,p2);
14
15
//      while(1);
16
}




Gerald K. schrieb:
> Werden zwei Instanzen des Programms gestartet, dann hat die Zeichenkette
> "100" zwei verschiedene Adressen.

Da muss ich mich korregieren. Ich habe ein kurzes Testpfogramm 
geschrieben um diesen Fall zu analysieren. Die Adressen sind relativ zum 
Programmcode und daher immer gleich!

Jörg W. schrieb:
> Es gibt Optimierungsstufen, bei denen der Compiler das genau so umsetzt
> (und daher "true" ermittelt)

Da wurde die Optimierung tatsächlich an die Spitze getrieben.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
>> Meiner Meinung nach ist die Codezeile sinnloser Bullshit den
>> keine Regel von C beschreibt.

> Ich kenne keine Regel, die diese Zeile verbietet.

Dass stimmt.

Doch die C Spezifikation ist wie Datenblätter von Mikrochips. Wenn bei 
einem IC z.B. nicht festgelegt ist, wie vie mA die ESD Schutzdioden 
vertragen, dann sollte man sie gar nicht absichtlich belasten. Denn das 
kann heute 20mA sein und in der nächsten Charge nur 2mA.

Dein eigentliches Problem ist, dass es hier eine Lücke in der 
Spezifikation gibt. Du willst eine lückenlose Spezifikation. So ist C 
aber nicht und so wird es nie werden. Wenn dir das wirklich wichtig ist, 
musst du eine andere Programmiersprache wählen.

Bei Java hat man sich bewusst um eine weitgehend Lückenlose 
Spezifikation bemüht, damit Programme auf jeder Maschine gleich laufen 
(funktioniert in der Praxis leider nicht, aber zumindest hat man es 
versucht).

Bei C hat man bewusst viele Details nicht festgelegt, damit die 
Umsetzung auf allen damals relevanten Maschinen problemlos möglich ist. 
Die Konsequenz ist: Verlasse dich nie darauf, dass eine 
nicht-spezifizierte Eigenschaft woanders oder in Zukunft ebenso ist.

von A. S. (Gast)


Lesenswert?

Jemand schrieb:
> In 6.7.9 Initialization: [..] indeterminate.

Ja, indeterminate ist klar. Du hast daraus gefolgert:

Jemand schrieb:
> dürfen also eine trap representation enthalten,

und ich frage, ob es nach 3.19.2 ff (@C11) nicht "unspecified value" 
ist.
A. S. schrieb:
> 3.19.2 indeterminate value
> either an unspecified value or a trap representation

Dann wäre es kein U.B. und das Ergebnis zwar zufällig aber ansonsten 
unkritisch.

von A. S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Dein eigentliches Problem ist, dass es hier eine Lücke in der
> Spezifikation gibt.

Wieso Lücke? Der Original-Code ist normaler, perfekter C-Code. Dass das 
Ergebnis zufällig ist, hat nichts mit Spezifikation zu tun. Es ist 
genauso zufällig, wie die Adresse einer Funktion oder eines ints. Wenn 
ich die in ein uint8 caste und auf > 100 teste, dann kann sich das 
Ergebnis auch mit der Optimierungsstufe ändern.

von Peter D. (peda)


Lesenswert?

In der Praxis hat man aber nicht nur 2 Strings in einem Programm. Und 
dann kann der Compiler zufällig entscheiden, wo er einen Substring 
plaziert.
Daher ist dieser Code sinnlos.

Beitrag #6749237 wurde von einem Moderator gelöscht.
Beitrag #6749239 wurde von einem Moderator gelöscht.
von Klaus W. (mfgkw)


Lesenswert?

A. S. schrieb:
> Wieso Lücke? Der Original-Code ist normaler, perfekter C-Code.

Kommt auf deine Ansprüche bei "perfekt" an.

Schon im K&R (2. Aufl., dt, S. 99 5.4 Adreß-Arithmetik) steht:
... Wenn p und q auf Elemente im gleichen Vektor zeigen, dann 
funktionieren Vergleiche wie ==, !=, <, >= usw.
...
Der Ablauf ist jedoch undefiniert bei Arithmetik oder Vergleichen 
zwischen Zeigern, die nicht auf Elemente des gleichen Vektors verweisen. 
(Es gibt eine Ausnahme: die Adresse des ersten Elements nach dem Ende 
eines Vektors kann für Zeigerarithmetik verwendet werden.
...

Ok, auch K&R sind nicht immer perfekt. Aber als Richtschnur kann man das 
schon mal nehmen.

von Al Fine (Gast)


Lesenswert?

Klaus W. schrieb:
> Schon im K&R (2. Aufl., dt, S. 99 5.4 Adreß-Arithmetik) steht:
> ... Wenn p und q auf Elemente im gleichen Vektor zeigen, dann
> funktionieren Vergleiche wie ==, !=, <, >= usw.
> ...
> Der Ablauf ist jedoch undefiniert bei Arithmetik oder Vergleichen
> zwischen Zeigern, die nicht auf Elemente des gleichen Vektors verweisen.
> (Es gibt eine Ausnahme: die Adresse des ersten Elements nach dem Ende
> eines Vektors kann für Zeigerarithmetik verwendet werden.
> ...
>
> Ok, auch K&R sind nicht immer perfekt. Aber als Richtschnur kann man das
> schon mal nehmen.

Kann man offenbar nicht. Eine Funktion
1
int f(int* p, int* q) { return p == q; }
ist immer wohldefiniert. Wenn ein Programm mit dieser Funktion spinnt, 
liegt der Fehler nicht in f.

Beitrag #6749355 wurde von einem Moderator gelöscht.
Beitrag #6749363 wurde von einem Moderator gelöscht.
Beitrag #6749371 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.