Könnte für einen Zeiger p im Extremfall p < p+1 falsch sein?

Lesezeit: 4 Minuten

Benutzeravatar von akarapatis
akarapatis

Ist es möglich, für eine Zeigervariable pdas p<(p+1) ist falsch? Bitte begründen Sie Ihre Antwort. Wenn ja, unter welchen Umständen kann dies passieren?

Ich habe mich gefragt, ob p + 1 überlaufen und gleich 0 sein könnte.

Z.B Auf einem 64-Bit-PC mit GCC-4.8 für ein Programm in der Sprache C:

int main(void) {
   void *p=(void *)0xFFFFFFFFFFFFFFFF;

   printf("p      :%p\n", p);
   printf("p+1    :%p\n", p+1);
   printf("Result :%d\n", p<p+1);
}

Es gibt zurück:

p      : 0xffffffffffffffff
p+1    : (nil)
Result : 0

Daher glaube ich, dass es in diesem Fall möglich ist. Bei einer ungültigen Zeigerposition kann dies passieren. Das ist die einzige Lösung, die mir einfällt. Gibt es andere?

Notiz:
Es werden keine Annahmen getroffen. Betrachten Sie jeden Compiler/Plattform/Architektur/Betriebssystem, bei dem die Möglichkeit besteht, dass dies passieren kann oder nicht.

  • Grundsätzlich ist das eine interessante Frage. Aber was sind deine Gedanken dazu?

    – Bathseba

    3. Dezember 2014 um 13:32 Uhr

  • @Borgleader Nein, ist es nicht! Diese Frage wurde mir bei einem Interviewfragebogen gestellt. Ich habe tagelang gegoogelt und keine eindeutige Antwort gefunden. Ich glaube, es ist eine faire Frage, auf Stackoverflow zu sein

    – akarapatis

    3. Dezember 2014 um 13:34 Uhr


  • @akarapatis Es ist meiner Meinung nach keine faire Frage, wie Sie sie jetzt stellen, aber sie könnte in eine faire Frage umformuliert werden.

    Benutzer743382

    3. Dezember 2014 um 13:36 Uhr

  • @barakmanos Die Frage ist ganz klar und es geht darum, was dir die Sprache garantiert. Die Sprache hat klare Definitionen dafür, was + und < für eine Zeigervariable bedeuten, es ist ziemlich irrelevant, welche Akarapatis-Definition von < für einen Zeiger ist oder ob Sie Zeiger als Ganzzahlen betrachten.

    – Nr

    3. Dezember 2014 um 14:30 Uhr


  • In C und C++, wenn p zeigt dann auf ein gültiges Objekt p<p+1 ist immer wahr. Ansonsten wenn p nicht auf ein Objekt zeigt, ist void* oder zeigt dann auf einen unvollständigen Typ p+1 ist undefiniert oder ein Kompilierzeitfehler, und daher ist ihr Vergleich UB oder unmöglich. Darüber hinaus gibt es Computerarchitekturen mit begrenzten Zeigern, und je nachdem, wie sie Zeiger codieren und wie sie auf Versuche reagieren, Out-of-Bounds-Zeiger zu erstellen, können Sie alles bekommen (p<p+1) falsch zu einem Absturz.

    – Ich werde nicht existieren Ich werde nicht existieren

    3. Dezember 2014 um 18:27 Uhr


Benutzeravatar von Mike Seymour
Mike Seymour

Ist es möglich, für eine Zeigervariable pdas p<(p+1) ist falsch?

Wenn p zeigt auf ein gültiges Objekt (dh eines, das gemäß dem C++-Objektmodell erstellt wurde) des richtigen Typs, dann nein. p+1 zeigt auf den Speicherort nach diesem Objekt und vergleicht immer größer als p.

Andernfalls sind das Verhalten sowohl der Arithmetik als auch des Vergleichs undefiniert, sodass das Ergebnis wahr, falsch oder gelb sein könnte.

Wenn ja, unter welchen Umständen kann dies passieren?

Es könnte passieren oder auch nicht

p = reinterpret_cast<char*>(numeric_limits<uintptr_t>::max);

Wenn Zeigerarithmetik wie vorzeichenlose Integer-Arithmetik funktioniert, kann dies zu einem numerischen Überlauf führen, z p+1 hat den Wert Null und vergleicht kleiner als p. Oder es könnte etwas anderes tun.

  • Kommentare sind nicht für längere Diskussionen gedacht; diese Konversation wurde in den Chat verschoben.

    – Tarin

    3. Dezember 2014 um 14:11 Uhr

  • „Gelbüberflutung“ gilt nur für Werte > 4.

    – Mike G

    3. Dezember 2014 um 22:05 Uhr

  • Ich würde die Aufmerksamkeit auf “undefiniert” lenken. In der Spezifikation wird ausdrücklich darauf hingewiesen, dass das Ergebnis jeder Zeigerarithmetik, die zu einem Überlauf führen würde, ein undefiniertes Verhalten ist. Undefiniertes Verhalten ist die fieseste „alles geht“-Antwort der Spezifikation. p<(p+1) Fälle sind gültig … ebenso Fälle, in denen es einfach sofort abstürzt, wenn Sie es versuchen.

    – Cort Ammon

    4. Dezember 2014 um 4:13 Uhr

  • @SteveJessop: In der Tat. Das ist alles in der Diskussion, die in den Chat verschoben wurde.

    – Mike Seymour

    4. Dezember 2014 um 14:53 Uhr

  • @Mike: ah, das habe ich nicht gelesen, weil es in den Chat verschoben wurde. Ich denke, was ich gesagt habe, ist eine lohnende Ergänzung / Klarstellung zu Ihrer Antwort, aber obv, wenn Sie es nicht ganz bei Ihnen machen wollen, werde ich es nicht bearbeiten.

    – Steve Jessop

    4. Dezember 2014 um 14:54 Uhr


Was ist, wenn ich unter DOS programmiere und eine weiter Zeiger (eines, das aus einem Segment und einem Offset besteht), und es zeigt auf die letzte Adresse im Segment, und ich füge eins hinzu, und den Zeiger umschlingt? Es sieht so aus, als würden Sie beim Vergleichen die Zeiger normalisieren, also den zweiten Zeiger p+1 wäre kleiner als p.

Dies ist jedoch ein Stich im Dunkeln, ich habe keinen DOS C-Compiler zum Testen zur Hand.

  • Die Segmentierung ist irrelevant – ein nicht segmentierter Zeiger kann auch umlaufen.

    – TonyK

    3. Dezember 2014 um 13:49 Uhr

  • Nicht komplett. Je nach Speichermodell können Sie Objekte haben, die Segmentierungsgrenzen überschreiten. In dem huge Speichermodell ist das Inkrementieren eines Zeigers auf die letzte Adresse in einem Segment gültig, da Arrays dort Segmentgrenzen überschreiten können. Das bedeutet, dass der Compiler auf Überlauf prüfen und den Segmentteil entsprechend anpassen muss. Mit unsegmentierten Zeigern können Sie nicht umbrechen nullptr.

    – MSalter

    3. Dezember 2014 um 14:38 Uhr

Ganz einfach: Es kann nicht passieren, wenn kein undefiniertes Verhalten im Spiel ist. Es kann sehr leicht passieren, wenn undefiniertes Verhalten vorliegt. Einzelheiten finden Sie in einer Kopie des C-Standards oder des C++-Standards.

Folglich darf ein konformer Compiler den <-Operator überhaupt nicht auswerten und stattdessen 1 oder true als Ergebnis verwenden. Dasselbe gilt für Arithmetik mit vorzeichenbehafteten Ganzzahlen (jedoch nicht für vorzeichenlose Ganzzahlen, bei denen es möglich ist, dass ein vollständig gültiger Code x > x+1 hat).

Ihr Beispielcode ist nicht einmal C oder C++, also scheinen Sie den Compiler in einem Modus verwendet zu haben, in dem es sich nicht um einen standardkonformen C- oder C++-Compiler handelt.

  • Im Allgemeinen mein Punkt, unter welchen Umständen dies passieren kann. Wie @Basile Starynkevitch in seiner Antwort erwähnte, besteht bei einer freistehenden Implementierung die Möglichkeit, dass dies passieren kann. Ich verstehe, dass es für Code, der mit einem konformen Compiler auf einem Betriebssystem kompiliert wurde, keine Chance gibt. Ich weiß, dass mein “Beispiel” zu stark vereinfacht und ungültig war, aber durch die Diskussion habe ich gehofft, mehr Einblick zu bekommen

    – akarapatis

    4. Dezember 2014 um 16:26 Uhr

Benutzeravatar von Basile Starynkevitch
Basile Starynkevitch

Es könnte mit einem ungültigen Zeiger passieren.

Aber wenn der Zeiger auf einen gültigen Speicherort zeigt, ist dies bei vielen Betriebssystemen (z. B. Linux) der Fall passiert praktisch nie (Zumindest wenn die sizeof(*p) ist nicht zu groß), weil in der Praxis Die ersten und letzten Seiten des Adressraums werden nie zugeordnet (aber Sie könnten eine Zuordnung mit erzwingen mmap & MAP_FIXED).

Für freistehende Implementierungen (z Innerhalb einem Kernel oder auf einem Mikrocontroller), sind die Dinge anders und implementierungsspezifisch (möglicherweise undefiniertes Verhaltenoder unspezifisches Verhalten).

Benutzeravatar von HappyCactus
HappyCactus

Gemäß Pointer-Vergleichen in C. Sind sie signiert oder unsigniert? bei Stapelüberlauf:

Sie können beliebige Zeiger in C/C++ nicht legal vergleichen. Das Ergebnis eines solchen Vergleichs ist nicht definiert.

  • Aus dem von Ihnen erwähnten Beitrag: “Die C-Sprache (sowie C ++) definiert Zeigervergleiche nur für Zeiger, die auf dasselbe Aggregat (Struktur oder Array) zeigen” – ich glaube, ich beziehe mich auf denselben Zeiger.

    – akarapatis

    3. Dezember 2014 um 15:11 Uhr

  • Ich bin mir nicht sicher: p und p+1 sind void *, also beziehen sie sich nicht auf ein Array (wie es wäre, wenn sie char * oder irgendetwas * wären). Jedenfalls hast du eine interessante Frage aufgeworfen.

    – HappyCactus

    3. Dezember 2014 um 15:21 Uhr

  • @HappyCactus: Die Frage gibt nicht an, dass p eine Leere ist * (es gibt ein Beispiel für eine Leere * p, aber die Frage selbst ist allgemein formuliert …)

    – Psmärchen

    3. Dezember 2014 um 17:51 Uhr

  • Aus dem von Ihnen erwähnten Beitrag: “Die C-Sprache (sowie C ++) definiert Zeigervergleiche nur für Zeiger, die auf dasselbe Aggregat (Struktur oder Array) zeigen” – ich glaube, ich beziehe mich auf denselben Zeiger.

    – akarapatis

    3. Dezember 2014 um 15:11 Uhr

  • Ich bin mir nicht sicher: p und p+1 sind void *, also beziehen sie sich nicht auf ein Array (wie es wäre, wenn sie char * oder irgendetwas * wären). Jedenfalls hast du eine interessante Frage aufgeworfen.

    – HappyCactus

    3. Dezember 2014 um 15:21 Uhr

  • @HappyCactus: Die Frage gibt nicht an, dass p eine Leere ist * (es gibt ein Beispiel für eine Leere * p, aber die Frage selbst ist allgemein formuliert …)

    – Psmärchen

    3. Dezember 2014 um 17:51 Uhr

1407980cookie-checkKönnte für einen Zeiger p im Extremfall p < p+1 falsch sein?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy