[C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

[C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Hi,

angenommen ich habe zwei Arrays:

  int foo[100];
  int bar[50];


und einen Zeiger:

  int * pX;

Nun würde ich gern herausfinden, zu welchem Array der Zeiger gehört:

  if(pX >= foo && pX <= foo + 100)
    …; //
Zeiger liegt in foo
  else if(pX >= bar && pX <= bar + 50)
    …; //
Zeiger liegt in bar

Ist das gültiges C++ oder dürfen Zeiger grundsätzlich nur mit dem Array verglichen werden, in dem das verwiesene Objekt tatsächlich liegt?

Das würde mir viel Arbeit sparen; ich will nur nicht, dass es jetzt zufällig funktioniert und ein zukünftiger Compiler die Vergleiche als undefiniertes Verhalten wegoptimiert.

Gruß
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

Es ist nicht undefined, aber unspecified:
ISO/IEC 14882:2011 §5.9/2 hat geschrieben:- If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified.
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Ist in Wikipedia sogar als Beispiel für unspecified behaviour gegeben … vielen Dank :-) In C ist es übrigens sogar undefined.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
dawit
Beiträge: 42
Registriert: 05.02.2011, 17:06

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dawit »

Ok, das ist jetzt ein Beispiel, das so trivial ist, dass ich nicht mal auf die Idee gekommen wäre nachzufragen. Ich sehe jetzt aber irgendwie immer noch nicht, was beim vergleichen eines Zeigers mit einem Array zu Problemen führen könnte. Kann mich jemand erleuchten?
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

Das Problem ist, Zeiger, die in zwei verschiedene Objekte zeigen, zu vergleichen. Zwei Zeiger, die in das selbe Array zeigen, sind kein Problem... ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Grundlage ist erst einmal, dass C++ keine Adressen kennt, sondern nur Zeiger. Adressen sind eine Art und Weise, wie man Zeiger implementieren kann (ein Implementation Detail) – aber nicht die Einzige.

Darum räumt der C++-Standard zum Beispiel ein, dass Zeiger je nach Objekt, auf das sie zeigen, unterschiedlich groß sein können: In einigen Implementierungen kann sizeof(int) != sizeof(char) gelten. Landläufig ist int oft vier Mal so groß wie char. Einem Compiler wäre damit erlaubt, int-Zeiger zwei Bits kleiner zu machen als char-Zeiger – weil vier Mal so viele chars in den Speicher passen wie ints, braucht man auch zwei Bits mehr (entsprechende Ausrichtung angenommen). reinterpret_cast<char *>(intPtr) müsste zwei Bits mehr reservieren und den Eingangswert mit vier Multiplizieren.

Das lehrt uns, dass Zeiger ziemlich abstrakte Dinge sind, und nicht immer bloß fortlaufende Speicheradressen. Das ist nötig weil nicht alle Architekturen mit einem einzigen fortlaufenden Adressraum arbeiten, sondern durchaus float in logisch anderen Bereichen (mit komplett anderer Art der Adressierung) speichern dürfen als int, oder Daten in anderen Bereichen als Code (das nennt man Harvard-Architektur), oder in Mehrprozessorsystemen jeder Prozessor seinen eigenen Speicher pflegen darf (NUMA). Oder Compiler können spezielle Debug-Funktionen anbieten, um jeden deiner Zugriffe auf Gültigkeit zu prüfen, und müssen dafür noch ndere (Debug-)Sachen in Zeiger stecken.

Folge davon ist, dass >, <, >=, und <= nur für Zeiger anwendbar ist, die im selben Array liegen. Falls eine Architektur z.B. Arrays, die größer als 1 KiB sind, in logisch komplett anderen Speicher steckt als kleine Arrays oder einzelne Objekte, lassen sie sich auch nicht vergleichen: Welche Art von Speicher wäre in diesem Fall „kleiner“? „Kleiner“ funktioniert nur bei Dingen, die sequenziell sind – was C++ eben bloß für einzelne Arrays garantiert, um auch stark heterogene Architekturen unterstützen zu können.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
dawit
Beiträge: 42
Registriert: 05.02.2011, 17:06

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dawit »

Danke für die ausführliche Antwort! Kennst du irgendwelche Architekturen, die unterschiedliche Speicherbereiche für bestimmte Datentypen/Array-Größen verwenden?
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Keine Ahnung – ich denke, dass du da bei Mikrocontrollern und alten Spielekonsolen am ehesten fündig wirst.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Sternmull »

Jetzt frag ich mich natürlich wie sowas wie memmove dann effizient feststellen soll ob sich der Speicherbereich von Ziel und Quelle überlappt.
Und ganz ehrlich: Ich würde an der Stelle nicht auf den Standard achten und die Tatsache nutzen das es in der Praxis funktioniert.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

Beachte: Es ist unspecified, nicht undefined. Unspecified heißt, dass ein Programm das tun darf, nur das Ergebnis der jeweiligen Implementierung überlassen ist (aber es gibt ein Ergebnis!). memmove ist Teil der Implementierung und wird natürlich alle Eigenschaften der jeweiligen Architektur ausnutzen, wie z.B. dass Pointer am Ende nur Integer sind...
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Sternmull hat geschrieben:Jetzt frag ich mich natürlich wie sowas wie memmove dann effizient feststellen soll ob sich der Speicherbereich von Ziel und Quelle überlappt.
  • memmove() ist im Standard damit du eine portable Lösung benutzen kannst statt dich selber um „Überlappen die sich?“ auf bestimmten Plattformen kümmern zu müssen.
  • memmove() kann immer ganz strunzdoof als Byte-weise Kopie implementiert sein. Dass memmove() schneller sein muss sobald sich die Bereiche nicht überlappen ist nirgends vorgeschrieben.
Und ganz ehrlich: Ich würde an der Stelle nicht auf den Standard achten und die Tatsache nutzen das es in der Praxis funktioniert.
Dann guckst du nur dumm aus der Wäsche wenn die nächste Version deines C-Compilers die ifs als undefiniertes Verhalten schlicht und einfach löscht. In C++ ist es nicht spezifiziert, was wohl bedeutet, dass einem tatsächlich nichts anderes als Ausprobieren übrig bleibt :( Es hätte aber auch anders sein können (siehe C), darum habe ich gefragt.

Nachtrag: dot war schneller, und kürzer, und deutlicher :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von TGGC »

Krishty hat geschrieben:Einem Compiler wäre damit erlaubt, int-Zeiger zwei Bits kleiner zu machen als char-Zeiger – weil vier Mal so viele chars in den Speicher passen wie ints, braucht man auch zwei Bits mehr (entsprechende Ausrichtung angenommen). reinterpret_cast<char *>(intPtr) müsste zwei Bits mehr reservieren und den Eingangswert mit vier Multiplizieren.
Sry, aber du erzaehlst Unsinn. Wenn das wirklich der Fall waere, so koennten die Vergleiche weiterhin problemlos funktionieren. Man koennte naemlich einfach den beschriebenen cast machen und dann vergleichen...
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

dawit hat geschrieben:Danke für die ausführliche Antwort! Kennst du irgendwelche Architekturen, die unterschiedliche Speicherbereiche für bestimmte Datentypen/Array-Größen verwenden?
Ein Beispiel wären wohl GPUs, da gibt's verschiedene Speicherbereiche für verschiedene Zwecke. Mittlerweile haben die aber auch schon einen Unified Address Space...
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

TGGC hat geschrieben:
Krishty hat geschrieben:Einem Compiler wäre damit erlaubt, int-Zeiger zwei Bits kleiner zu machen als char-Zeiger – weil vier Mal so viele chars in den Speicher passen wie ints, braucht man auch zwei Bits mehr (entsprechende Ausrichtung angenommen). reinterpret_cast<char *>(intPtr) müsste zwei Bits mehr reservieren und den Eingangswert mit vier Multiplizieren.
Sry, aber du erzaehlst Unsinn. Wenn das wirklich der Fall waere, so koennten die Vergleiche weiterhin problemlos funktionieren. Man koennte naemlich einfach den beschriebenen cast machen und dann vergleichen...
Ja; in diesem Fall würde das noch gehen. Das Beispiel sollte aber nur zeigen, dass Zeiger nicht nötigerweise homogene Adressen sind. Danach kam das Beispiel mit den getrennten Adressräumen, und dann funktionieren auch die char *-Casts nicht mehr.
dot hat geschrieben:
dawit hat geschrieben:Danke für die ausführliche Antwort! Kennst du irgendwelche Architekturen, die unterschiedliche Speicherbereiche für bestimmte Datentypen/Array-Größen verwenden?
Ein Beispiel wären wohl GPUs, da gibt's verschiedene Speicherbereiche für verschiedene Zwecke. Mittlerweile haben die aber auch schon einen Unified Address Space...
Und ein dickes Problem ist, dass man es nicht einfach bei undefiniertem Verhalten belassen, sondern den Anwender schon beim Kompilieren warnen möchte, wenn er was falsch macht. OpenCL C braucht zu diesem Zweck vier Address Space Qualifiers bei Zeigerdeklarationen: __local, __global, __constant, und __private.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
antisteo
Establishment
Beiträge: 854
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von antisteo »

Krishty hat geschrieben:Hi,

angenommen ich habe zwei Arrays:

  int foo[100];
  int bar[50];


und einen Zeiger:

  int * pX;

Nun würde ich gern herausfinden, zu welchem Array der Zeiger gehört:

  if(pX >= foo && pX <= foo + 100)
    …; //
Zeiger liegt in foo
  else if(pX >= bar && pX <= bar + 50)
    …; //
Zeiger liegt in bar
du könntest sogar die Hälfte der Vergleiche rausschmeißen, da du ja weißt, in welcher Reihenfolge die Arrays auf dem Stack liegen ;)
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
antisteo
Establishment
Beiträge: 854
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von antisteo »

Krishty hat geschrieben:Das würde mir viel Arbeit sparen; ich will nur nicht, dass es jetzt zufällig funktioniert und ein zukünftiger Compiler die Vergleiche als undefiniertes Verhalten wegoptimiert.
Wegoptimiert wird es bestimmt nicht, da der Code für einen Außenstehenden wie ein Rangecheck aussieht. Und Rangechecks werden nur herausoptimiert werden, wenn die Sprache implizite Rangechecks schon drin hätte (managed Code), was aber bei C/C++ wohl nie der Fall werden wird.
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Doch; natürlich wird es das. Es gab mal ein Memo einer US-Behörde, die mit Range Checks gegen Pufferüberläufe sichern wollte, und dann blöd geguckt hat, als GCC die alle durch if(true) ersetzt hat. Clang optimiert undefiniertes Verhalten noch aggressiver weg (insbesondere Nullzeigerprüfungen). Darum sollte man solchen Quelltext unter C auf gar keinen Fall benutzen.

Dies:

  if(pX >= foo && pX < foo + 100)
    *pX = 0;


wird von modernen C-Optimizern so interpretiert:
  • pX wird mit dem Array foo verglichen.
  • Ein Zeiger darf mit anderen Zeigern nur verglichen werden, falls sie auf dasselbe Objekt (in diesem Fall: das Array foo) zeigen.
  • Zeigt pX nicht auf ein Element von foo, ist das Programm undefiniert. Dann dürfen wir tun, was wir wollen.
  • Wir entscheiden uns, dann das selbe zu tun wie in dem Fall, wo pX tatsächlich auf foo zeigt.
Ergebnis:

  *pX = 0; // if eliminiert
antisteo hat geschrieben:du könntest sogar die Hälfte der Vergleiche rausschmeißen, da du ja weißt, in welcher Reihenfolge die Arrays auf dem Stack liegen ;)
Nichts garantiert, dass lokale Variablen in Deklarationsreihenfolge im Speicher liegen :( Denk daran, dass Stapelspeicher nur eine mögliche Art ist, die von C++ abstrakt vorgeschriebene Zerstörungsreihenfolge zu realisieren – aber nicht die einzige.

Dass es einen Stack gibt ist ein Implementierungsdetail und wird von C++ nirgends erwähnt. Es beginnt ja schon damit, dass der Stack auf x86 üblicherweise von hohen Adressen zu niedrigen wächst, während Arrays von niedrigen Adressen zu hohen verlaufen. Das erste Array liegt also hier bei mir höher im Speicher – es sei denn, ich packe es in ein Objekt; dann umgekehrt …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von BeRsErKeR »

Ein Compiler optimiert undefiniertes Verhalten weg? Das ist ja schrecklich. Ich würde erwarten, dass in diesem Fall ein Laufzeitfehler kommt und nicht einfach irgendwas am Verhalten geändert wird. Und bei deinem Code würde ich eigentlich so viel Intelligenz beim Compiler voraussetzen, dass er das eindeutig zu true oder false auflösen kann, ganz unabhängig ob das spezifiziert ist, denn es ist völlig unabhängig vom Speicherort oder der Implementierung möglich festzustellen, ob der Pointer Teil des Arrays ist oder nicht. Und wenn er dies nicht ist, dann ist diese Bedingung halt auch false. Das ist einfach ein gewisse Logik, die da von Nöten ist. Schöner wäre natürlich ein Operator ala ptr is_inside_of arr.
Ohne Input kein Output.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

BeRsErKeR hat geschrieben:Ich würde erwarten, dass in diesem Fall ein Laufzeitfehler kommt und nicht einfach irgendwas am Verhalten geändert wird.
In einem Programm mit undefiniertem Verhalten, gibt es kein Verhalten, an dem sich etwas ändern könnte, denn das Verhalten ist ja undefiniert...
BeRsErKeR hat geschrieben:Und bei deinem Code würde ich eigentlich so viel Intelligenz beim Compiler voraussetzen, dass er das eindeutig zu true oder false auflösen kann, ganz unabhängig ob das spezifiziert ist, denn es ist völlig unabhängig vom Speicherort oder der Implementierung möglich festzustellen, ob der Pointer Teil des Arrays ist oder nicht.
Moment, bei der Pointer in Array Sache ist das Verhalten (in C++) nur unspezifiziert, das ist etwas anderes als undefiniertes Verhalten. Im Falle von unspezifiziertem Verhalten, gibt es zumindest irgendein implementierungsabhängiges Verhalten, welches, je nach Implementierung, beispielsweise das von dir erwartete Verhalten sein könnte...

Es gibt keine allgemeinen Garantien bezüglich der relativen Platzierung verschiedener, unabhängiger Objekte im Speicher; spätestens bei Objekten, die am free store (heap) angelegt wurden, wirst du feststellen, dass es selbst im Rahmen einer konkreten Implementierung (z.b. MSVC auf x64) keinen Weg gibt, irgendwelche sinnvollen Garantien diesbezüglich überhaupt auch nur zu beschreiben. Ohne solche lässt sich allerdings für <, <=, > und >= kein sinnvolles Verhalten definieren...

Code: Alles auswählen

A* a = new A;
B* b = new B;

if (a < b)
  // ???
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von BeRsErKeR »

dot hat geschrieben:
BeRsErKeR hat geschrieben:Ich würde erwarten, dass in diesem Fall ein Laufzeitfehler kommt und nicht einfach irgendwas am Verhalten geändert wird.
In einem Programm mit undefiniertem Verhalten, gibt es kein Verhalten, an dem sich etwas ändern könnte, denn das Verhalten ist ja undefiniert...
Ich dachte das Verhalten ist nur dann undefiniert, wenn der Pointer eben nicht im Array liegt und das wird ja u.U. erst zur Laufzeit festgestellt. Der Code sollte ja sowohl in C als auch C++ definiert sein, falls man mit dem Array testet, in dem der Pointer tatsächlich liegt. Oder habe ich das falsch verstanden? Das heißt das Verhalten ändert sich je nachdem ob der Pointer im Array liegt oder nicht.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Und bei deinem Code würde ich eigentlich so viel Intelligenz beim Compiler voraussetzen, dass er das eindeutig zu true oder false auflösen kann, ganz unabhängig ob das spezifiziert ist, denn es ist völlig unabhängig vom Speicherort oder der Implementierung möglich festzustellen, ob der Pointer Teil des Arrays ist oder nicht.
Moment, bei der Pointer in Array Sache ist das Verhalten (in C++) nur unspezifiziert, das ist etwas anderes als undefiniertes Verhalten. Im Falle von unspezifiziertem Verhalten, gibt es zumindest irgendein implementierungsabhängiges Verhalten, welches, je nach Implementierung, beispielsweise das von dir erwartete Verhalten sein könnte...
Ja aber in C wäre das ganze aus logischer Sicht genauso gut realisierbar. Der Compiler müsste halt erkennen, dass hier geprüft werden soll, ob der zeiger im Array liegt oder nicht. Ich will damit sagen, wenn der Compiler hier sowieso was wegoptimiert, dann könnte er doch durch etwas Logik hier so optimieren, dass er erkennt, was der Programmierer bezwecken will. Denn dann könnte er eindeutig true oder false liefern.
dot hat geschrieben:Es gibt keine allgemeinen Garantien bezüglich der relativen Platzierung verschiedener, unabhängiger Objekte im Speicher; spätestens bei Objekten, die am free store (heap) angelegt wurden, wirst du feststellen, dass es selbst im Rahmen einer konkreten Implementierung (z.b. MSVC auf x64) keinen Weg gibt, irgendwelche sinnvollen Garantien diesbezüglich überhaupt auch nur zu beschreiben. Ohne solche lässt sich allerdings für <, <=, > und >= kein sinnvolles Verhalten definieren...

Code: Alles auswählen

A* a = new A;
B* b = new B;

if (a < b)
  // ???
Ja wenn man das allgemein auf Vergleichsoperatoren bezieht mag das ja stimmen, aber Vergleichsoperatoren auf Pointer dienen doch eigentlich immer zur Feststellung, ob der Pointer in einem bestimmten Bereich liegt (relativ zu einem anderen Pointer/Array). Wenn ich also prüfe ob Pointer x im (zusammenhängenden) Bereich y liegt, dann ist es völlig egal wo der liegt. Es ist immer eindeutig möglich festzustellen, ob x im Bereich y liegt oder nicht. Man vergleicht ja relativ mit einem Bereich und nicht absolut. Die Sprachmittel von C/C++ sind hier vielleicht etwas ungeeignet, aber von der Theorie her ist dieser Vergleich absolut unproblematisch, sofern man mit Bereichen prüft, die sequenziell hintereinander liegen (was Arrays ja bekanntlich tun).

Ich meine damit, dass der Compiler die Prüfung im if einfach in eine relative Bereichsprüfung umoptimieren könnte, die dann in jedem Fall eindeutig ist. Das Problem mit der Undefiniertheit kommt ja nur durch die Forderung nach einer absoluten Positionierung zu stande. Eine Prüfung darauf, ob ein Pointer innerhalb eines Bereiches liegt, ist ja einfach lösbar, indem zwischen Anfang und Ende des Bereiches nach dem Pointer gesucht wird. Dazu ist ggf. ein Mapping in den jeweiligen realen Speicherbereich erforderlich, undefiniert ist es dann aber nicht mehr.

Ich weiß, dass das natürlich dann nicht gilt, wenn man einfach nur auf kleiner oder größer prüft, aber wozu sollte man prüfen ob ein Pointer kleiner ist als ein anderer, wenn er nicht innerhalb des selben Objekts / Arrays liegt? Hier ist unspezifiziertes Verhalten wahrscheinlich ok, aber eine Bereichsprüfung könnte ein Compiler immer eindeutig auflösen.
Ohne Input kein Output.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

BeRsErKeR hat geschrieben:Ich dachte das Verhalten ist nur dann undefiniert, wenn der Pointer eben nicht im Array liegt und das wird ja u.U. erst zur Laufzeit festgestellt.
Ja, ein konkreter Compiler auf einer konkreten Architektur wird dies in vielen Fällen erst zur Laufzeit feststellen können...das heißt nicht, dass das im Allgemeinen so ist. Im Allgemeinen lässt sich das nicht klar sagen...
BeRsErKeR hat geschrieben:Der Code sollte ja sowohl in C als auch C++ definiert sein, falls man mit dem Array testet, in dem der Pointer tatsächlich liegt. Oder habe ich das falsch verstanden? Das heißt das Verhalten ändert sich je nachdem ob der Pointer im Array liegt oder nicht.
So lange die beiden verglichenen Pointer in das selbe Objekt zeigen, ist das Verhalten sowohl in C als auch in C++ definiert, denk ich. Problematisch wird es, sobald die Pointer eben nichtmehr beide in das selbe Objekt zeigen. Der Fall ist in C undefiniert und in C++ unspezifiziert.
BeRsErKeR hat geschrieben:Ja aber in C wäre das ganze aus logischer Sicht genauso gut realisierbar. Der Compiler müsste halt erkennen, dass hier geprüft werden soll, ob der zeiger im Array liegt oder nicht. Ich will damit sagen, wenn der Compiler hier sowieso was wegoptimiert, dann könnte er doch durch etwas Logik hier so optimieren, dass er erkennt, was der Programmierer bezwecken will. Denn dann könnte er eindeutig true oder false liefern.
Nichts hindert den Compiler daran, dies zu tun, wenn er es kann. Es ist dennoch undefiniertes Verhalten, d.h. ein anderer Compiler darf beim Übersetzen von solchem Code stattdessen gerne auch lustige Musik spielen und Feuer fangen, eine exe produzieren, die nur nicht crashed, wenn Dienstag in einer Woche Vollmond ist etc.
BeRsErKeR hat geschrieben:Ja wenn man das allgemein auf Vergleichsoperatoren bezieht mag das ja stimmen, aber Vergleichsoperatoren auf Pointer dienen doch eigentlich immer zur Feststellung, ob der Pointer in einem bestimmten Bereich liegt (relativ zu einem anderen Pointer/Array).
Vergleichsoperatoren auf Pointer dienen im Allgemeinen dazu, Pointer zu vergleichen.
BeRsErKeR hat geschrieben:Wenn ich also prüfe ob Pointer x im (zusammenhängenden) Bereich y liegt, dann ist es völlig egal wo der liegt. Es ist immer eindeutig möglich festzustellen, ob x im Bereich y liegt oder nicht.
Nur weil es auf einem PC so ist, muss es noch lange nicht im Allgemeinen auch so sein. Dein Missverständnis beruht wohl darauf, dass du davon ausgehst, dass es immer und überall genau nur einen großen, zusammenhängenden Addressraum geben muss...
BeRsErKeR hat geschrieben:Man vergleicht ja relativ mit einem Bereich und nicht absolut. Die Sprachmittel von C/C++ sind hier vielleicht etwas ungeeignet, aber von der Theorie her ist dieser Vergleich absolut unproblematisch, sofern man mit Bereichen prüft, die sequenziell hintereinander liegen (was Arrays ja bekanntlich tun).
Ok jetzt bin ich verwirrt. So lange du nur Pointer vergleichst, die alle in das selbe Array zeigen, ist das alles natürlich kein Problem und wohldefiniert. Problematisch ist der Vergleich von Pointern, die nicht in das selbe Array zeigen...
BeRsErKeR hat geschrieben:Ich weiß, dass das natürlich dann nicht gilt, wenn man einfach nur auf kleiner oder größer prüft [...]
Und genau das tun diese Operatoren... ;)
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von TGGC »

Man koennte die Arrays auch auf einem Heap packen, der nach dem Start der Arrays sortiert ist und wuerde dann in amortisierter Laufzeit von log n das passende Array finden. Oh, genau das passiert wenn man new und delete auf die Zeiger aufruft, na so ein Zufall...
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dot »

TGGC hat geschrieben:Oh, genau das passiert wenn man new und delete auf die Zeiger aufruft, na so ein Zufall...
Genau das passiert auf deinem PC...im C++ Standard steht nichts von einem irgendwie sortiertem Heap, das Wort Heap wird dort (in diesem Kontext) nichtmal verwendet und von einem einzelnen, zusammenhängenden Adressraum steht dort auch nichts. Im C++ Standard steht allerdings auch nichts, das einem Compiler verbieten würde, auf einer entsprechenden Plattform entsprechend zu optimieren. Und die ursprüngliche Frage war nunmal, was der C++ Standard dazu sagt und nicht, was ein konkreter Compiler auf einer konkreten Plattform daraus machen wird. Wer das wissen will: Mit dem jeweiligen Compiler ausprobieren. Der Punkt ist, dass solcher Code zwar gültiges C++, aber nicht portabel ist. Ehrlich gesagt, würd ich mir aber ganz andere Gedanken machen, wenn mein Code über Vergleichsoperatoren feststellen müsste, in welches Objekt ein bestimmter Pointer zeigt...
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

dot hat geschrieben:Ehrlich gesagt, würd ich mir aber ganz andere Gedanken machen, wenn mein Code über Vergleichsoperatoren feststellen müsste, in welches Objekt ein bestimmter Pointer zeigt...
Ich versuche ganz im Gegenteil redundante Information zu vermeiden:

  struct Sample {
    char const * toPooledData;
    bool         is16Bit; //
IGITT!
  };
  …
  dispatch(sample.toPooledData, sample.is16Bit ? pcm16Bit : pcm8Bit);


Das verschwendet durch die eklige 9-Byte-Größe und das Padding glatt 40 % Speicher. is16Bit muss initialisiert und gepflegt werden. Meiner Meinung nach ist die Variable überflüssig, weil ich durch den Wert des Zeigers feststellen kann, auf welchen Pool verwiesen wird:

   struct Sample {
    char const * toPooledData;
  };
  …
  dispatch(sample.toPooledData, pointsToArray(sample.toPooledData, samplePool_16Bit) ? pcm16Bit : pcm8Bit);


verbraucht nur halb so viel Speicher und ich spare mir das Pflegen der bool.

Eine andere Möglichkeit wäre gewesen, 8-Bit-Samples absichtlich an unrunden Adressen abzulegen, und das letzte Bit des Zeigers zu prüfen:

  dispatch(sample.toPooledData, (reinterpret_cast<uintptr_t>(sample.toPooledData) % 2) ? pcm8Bit : pcm16Bit);

aber das hätte zusätzliche Komplexität beim Pooling bedeutet.

Normale Programmierer sollten natürlich eine virtuelle Methode benutzen ;-)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von BeRsErKeR »

dot hat geschrieben:
BeRsErKeR hat geschrieben:Wenn ich also prüfe ob Pointer x im (zusammenhängenden) Bereich y liegt, dann ist es völlig egal wo der liegt. Es ist immer eindeutig möglich festzustellen, ob x im Bereich y liegt oder nicht.
Nur weil es auf einem PC so ist, muss es noch lange nicht im Allgemeinen auch so sein. Dein Missverständnis beruht wohl darauf, dass du davon ausgehst, dass es immer und überall genau nur einen großen, zusammenhängenden Addressraum geben muss...
Nein das ist doch völlig egal. Wichtig ist nur, dass der Bereich, mit dem ich Vergleiche, zusammenhängend ist. Wenn z.B. Bereich A auf der GPU liegt und Bereich B irgendwo anders, dann kann ich dennoch eindeutig feststellen, ob Pointer x in Bereich A oder Bereich B liegt. Man darf einen Pointer halt nicht als absolute Adresse ansehen. So viel Logik traue ich einem modernen Compiler schon zu.
dot hat geschrieben:
BeRsErKeR hat geschrieben:Man vergleicht ja relativ mit einem Bereich und nicht absolut. Die Sprachmittel von C/C++ sind hier vielleicht etwas ungeeignet, aber von der Theorie her ist dieser Vergleich absolut unproblematisch, sofern man mit Bereichen prüft, die sequenziell hintereinander liegen (was Arrays ja bekanntlich tun).
Ok jetzt bin ich verwirrt. So lange du nur Pointer vergleichst, die alle in das selbe Array zeigen, ist das alles natürlich kein Problem und wohldefiniert. Problematisch ist der Vergleich von Pointern, die nicht in das selbe Array zeigen...
Ich rede vom Vergleich eines beliebigen Pointers mit einem zusammenhängenden Bereich (z.B. ein Array). Es ist eindeutig feststellbar, ob ein Pointer innerhalb eines solchens Bereiches liegt, wenn man sich von der Vorstellung verabschiedet, dass ein Pointer eine absolute Adresse ist. Wenn das Array auf einem bestimmten Medium liegt und dort einen bestimmten Adressraum belegt, dann kann man auch feststellen, ob der Pointer auf diesem Medium und in diesem Bereich liegt oder nicht.

Daher sagte ich ja auch, dass man natürlich nicht global auf kleiner oder größer prüfen kann, aber feststellen, ob sich ein Pointer in einem bestimmten Bereich befindet kann man immer.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Ich weiß, dass das natürlich dann nicht gilt, wenn man einfach nur auf kleiner oder größer prüft [...]
Und genau das tun diese Operatoren... ;)
Ja daher sagte ich ja, dass die Sprachmittel von C/C++ hier etwas ungeeignet sind. Ein Pointer-Vergleich ist ja nur sinnvoll um festzustellen, wo sich der Pointer gerade befindet. Niemand wird jemals wissen wollen, ob sich ein Pointer absolut vor oder hinter einem bestimmten Speicherbereich befindet, sondern nur ob er sich innerhalb oder außerhalb eines solchen befindet. Daher wäre viel zweckmäßiger dafür Operatoren bereitzustellen oder if-Abfragen (wie die von Krishty) so zu optimieren, dass sie das gewünschte Ergebnis liefern (denn in diesem Fall gibt es immer eine eindeutig Aussage).
Ohne Input kein Output.
antisteo
Establishment
Beiträge: 854
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von antisteo »

Krishty hat geschrieben:Doch; natürlich wird es das. Es gab mal ein Memo einer US-Behörde, die mit Range Checks gegen Pufferüberläufe sichern wollte, und dann blöd geguckt hat, als GCC die alle durch if(true) ersetzt hat. Clang optimiert undefiniertes Verhalten noch aggressiver weg (insbesondere Nullzeigerprüfungen). Darum sollte man solchen Quelltext unter C auf gar keinen Fall benutzen.

Dies:

  if(pX >= foo && pX < foo + 100)
    *pX = 0;


wird von modernen C-Optimizern so interpretiert:
  • pX wird mit dem Array foo verglichen.
  • Ein Zeiger darf mit anderen Zeigern nur verglichen werden, falls sie auf dasselbe Objekt (in diesem Fall: das Array foo) zeigen.
  • Zeigt pX nicht auf ein Element von foo, ist das Programm undefiniert. Dann dürfen wir tun, was wir wollen.
  • Wir entscheiden uns, dann das selbe zu tun wie in dem Fall, wo pX tatsächlich auf foo zeigt.
Ergebnis:

  *pX = 0; // if eliminiert
Wenn aber pX als fremder Wert hereinkommt, wird der Code stehen gelassen, da die Bedingung nicht konstant gefaltet werden kann.
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8247
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von Krishty »

Lies es nochmal: Wo pX herkommt ist egal. Da die Sprache nichts anderes erlaubt als ihn mit dem selben Array zu vergleichen worauf er auch tatsächlich zeigt, darf der Compiler annehmen, dass er immer auf das Array zeigt, mit dem er auch verglichen wird. Der Fall, dass der Zeiger nicht zum Array gehört, ist in einem wohldefinierten C-Programm nicht existent.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
dawit
Beiträge: 42
Registriert: 05.02.2011, 17:06

Re: [C++] Zeiger gegen fremdes Array vergleichen: Erlaubt?

Beitrag von dawit »

Habe gerade auf stackoverflow folgendes entdeckt:
20.3.3/8 in C++03 hat geschrieben:For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.
Damit müsste doch das ursprüngliche Problem standardkonform zu lösen sein, oder?

EDIT: Ok, ich sehe gerade, dass std::less etc. zwar auf jeden Fall ein Ergebnis liefern, aber dass muss ja noch lange nicht bedeuten, dass der Zeiger auch wirklich in einem bestimmten Bereich liegt. Wie die total order nun letztlich aussieht, wird ja nicht definiert.
Antworten