Hallo zusammen,
aus Langeweile habe ich mal einen gerade kursierenden Witz
ausprobiert/implementiert:
1
volatileinta="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:
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?
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?
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.
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.
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?
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.
> 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.
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.
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?
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.
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."
(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.
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.
(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
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?
@ 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.
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."
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.
(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
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.
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?
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.
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
inta,b,*ap,*bp;
2
ap=&a,bp=&b;
3
intc=*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.
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.
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 ;-)
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.
(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
inta,b,*ap,*bp;
2
ap=&a,bp=&b;
3
intc=ap==bp;
Bin zwar nicht so schnippisch wie ein Compiler, werde aber dafür
schneller müde.
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?
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.
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. ;-)
(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.
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.
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."
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
(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.
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.
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.
(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.
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.
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.
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.
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.
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.
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.
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
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
Oliver S. schrieb:> Der Abschnitt behandelt ausdrücklich den Vergleich von zwei Pointern,
Vergleich mit relational operators. Der Abschnitt behandelt nicht ==.
LG, Sebastian
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.
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.
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
(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ß.
(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!
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".
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.
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.
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.
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.
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.
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.
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.