Was ist der Datentyp uintptr_t?

Lesezeit: 9 Minuten

Was ist der Datentyp uintptr t
dimba

Was ist uintptr_t und wofür kann es verwendet werden?

1647123013 208 Was ist der Datentyp uintptr t
Steve Jessop

Als erstes, als die Frage gestellt wurde, uintptr_t war nicht in C++. Es ist in C99, in <stdint.h>, als optionaler Typ. Viele C++03-Compiler stellen diese Datei bereit. Es ist auch in C++11, in <cstdint>wobei es wiederum optional ist, und die sich für die Definition auf C99 bezieht.

In C99 ist es definiert als “ein vorzeichenloser ganzzahliger Typ mit der Eigenschaft, dass jeder gültige Zeiger auf void in diesen Typ konvertiert und dann wieder in einen Zeiger auf void konvertiert werden kann, und das Ergebnis gleich dem ursprünglichen Zeiger ist”.

Nehmen Sie dies so, wie es gemeint ist. Es sagt nichts über die Größe aus.

uintptr_t könnte die gleiche Größe haben wie a void*. Es könnte größer sein. Es könnte durchaus kleiner sein, obwohl eine solche C++-Implementierung pervers angeht. Zum Beispiel auf einer hypothetischen Plattform, wo void* 32 Bit ist, aber nur 24 Bit des virtuellen Adressraums verwendet werden, könnten Sie einen 24-Bit haben uintptr_t was die Anforderung erfüllt. Ich weiß nicht, warum eine Implementierung das tun würde, aber der Standard erlaubt es.

  • Danke für die ““. Meine Anwendung wurde aufgrund der uintptr_t-Deklaration nicht kompiliert. Aber wenn ich Ihren Kommentar lese, füge ich “#include ” hinzu und ja, jetzt funktioniert es. Danke!

    – JavaRunner

    12. Februar 2014 um 8:13 Uhr


  • Um beispielsweise ausgerichteten Speicher unter anderem zuzuweisen?

    – legends2k

    21. Juli 2015 um 7:36 Uhr

  • Ein weiterer häufiger Anwendungsfall für das Umwandeln eines Zeigers in ein Int ist das Erstellen eines undurchsichtigen Handles, das den Zeiger verbirgt. Dies ist nützlich, um einen Verweis auf ein Objekt von APIs zurückzugeben, bei denen Sie das Objekt für die Bibliothek privat halten und verhindern möchten, dass Anwendungen darauf zugreifen. Die Anwendung wird dann gezwungen, die API zu verwenden, um alle Operationen an dem Objekt auszuführen

    – Joel Cunningham

    5. Mai 2016 um 13:57 Uhr

  • @JoelCunningham: Das funktioniert, unterscheidet sich aber nicht wirklich von der Verwendung void*. Es wirkt sich jedoch auf mögliche zukünftige Richtungen aus, insbesondere wenn Sie etwas ändern möchten, das wirklich nur ein Integer-Handle ist, überhaupt kein konvertierter Zeiger.

    – Steve Jessop

    5. Mai 2016 um 14:19 Uhr


  • @CiroSantilli烏坎事件2016六四事件法轮功 Ein häufiger Anwendungsfall besteht darin, nur ein Int an eine API zu übergeben, die eine Leerstelle* für generische Daten erwartet. Spart Ihnen die Tastenanschläge typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;. Stattdessen: callback.dataPtr = (void*)val. Auf der anderen Seite bekommt man natürlich void* und muss es zurückwerfen int.

    – Francesco Dondi

    5. April 2017 um 12:09 Uhr

1647123014 256 Was ist der Datentyp uintptr t
Zeichner Dormann

uintptr_t ist ein vorzeichenloser ganzzahliger Typ, der einen Datenzeiger speichern kann. Was normalerweise bedeutet, dass es die gleiche Größe wie ein Zeiger hat.

Es ist optional in C++11 und späteren Standards definiert.

Ein häufiger Grund, einen ganzzahligen Typ zu wollen, der den Zeigertyp einer Architektur enthalten kann, besteht darin, ganzzahlspezifische Operationen an einem Zeiger auszuführen oder den Typ eines Zeigers zu verschleiern, indem er als ganzzahliges “Handle” bereitgestellt wird.

  • Beachten Sie, dass size_t muss nur ausreichen, um die Größe des größten Objekts aufzunehmen, und kann kleiner als ein Zeiger sein. Dies wäre auf segmentierten Architekturen wie dem 8086 (16 Bit size_taber 32 Bit void*)

    – MSalter

    4. Dezember 2009 um 9:08 Uhr

  • um die Differenz zwischen zwei Zeigern darzustellen, haben Sie ptrdiff_t. uintptr_t ist nicht dafür gedacht.

    – jalf

    4. Dezember 2009 um 14:44 Uhr

  • @jalf: Für den Unterschied, ja, aber für Distanzmöchten Sie einen vorzeichenlosen Typ.

    – Drew Dormann

    4. Dezember 2009 um 17:00 Uhr

  • Die uintptr_t-Definition ist anscheinend auch in C++11 nicht obligatorisch (also kein Standard)! cplusplus.com/reference/cstdint (Ich habe den Hinweis von Steve Jessops Antwort bekommen)

    – Antonio

    1. Oktober 2014 um 20:56 Uhr

  • @MarcusJ unsigned int ist meist nicht groß genug. Aber es könnte groß genug sein. Dieser Typ existiert speziell, um alle zu entfernen “annehmend”.

    – Drew Dormann

    31. Mai 2015 um 16:46 Uhr


Es ist ein vorzeichenloser Integer-Typ, der genau die Größe eines Zeigers hat. Wann immer Sie etwas Ungewöhnliches mit einem Zeiger tun müssen – wie zum Beispiel alle Bits invertieren (fragen Sie nicht warum), wenden Sie ihn an uintptr_t und manipulieren Sie es als eine übliche ganze Zahl, dann werfen Sie es zurück.

  • Natürlich könnten Sie das tun, aber das wäre natürlich ein undefiniertes Verhalten. Ich glaube, dann können Sie das Ergebnis einer Umwandlung in uintptr_t nur unverändert weitergeben und zurückwerfen – alles andere ist UB.

    – schleske

    13. Januar 2011 um 22:47 Uhr

  • Es gibt Zeiten, in denen Sie mit den Bits spielen müssen, und dies würde normalerweise Compilerfehler erzeugen. Ein gängiges Beispiel ist das Erzwingen von 16-Byte-ausgerichtetem Speicher für bestimmte video- und leistungskritische Anwendungen. stackoverflow.com/questions/227897/…

    – Wolke

    22. Juli 2014 um 21:48 Uhr

  • @sleske das stimmt nicht. Auf Maschinen mit selbstausgerichteten Typen sind die beiden niedrigstwertigen Bits eines Zeigers Null (weil Adressen Vielfache von 4 oder 8 sind). Ich habe Programme gesehen, die dies ausnutzen, um Daten zu komprimieren.

    – mrk

    3. Januar 2015 um 17:48 Uhr

  • @saadtaame: Ich habe gerade darauf hingewiesen, dass dies UB ist nach C-Norm. Das bedeutet nicht, dass es auf einigen Systemen nicht definiert werden kann – Compiler und Laufzeiten sind frei, ein bestimmtes Verhalten für etwas zu definieren, das UB in Standard-C ist. Es gibt also keinen Widerspruch :-).

    – schleske

    3. Januar 2015 um 18:34 Uhr

  • Es ist nicht unbedingt genau so groß wie ein Zeiger. Alle Standardgarantien bestehen darin, dass die Konvertierung von a void* Zeigerwert auf uintptr_t und wieder zurück ergibt a void* Wert, der dem ursprünglichen Zeiger entspricht. uintptr_t hat normalerweise die gleiche Größe wie void*, aber das ist weder garantiert, noch gibt es eine Garantie dafür, dass die Bits des konvertierten Werts eine bestimmte Bedeutung haben. Und es gibt keine Garantie dafür, dass es einen konvertierten Zeiger-zu-Funktion-Wert ohne Informationsverlust halten kann. Schließlich ist es nicht garantiert, dass es existiert.

    – Keith Thompson

    2. September 2017 um 20:28 Uhr

1647123015 811 Was ist der Datentyp uintptr t
BGR

Es gibt bereits viele gute Antworten auf “Was ist der Datentyp uintptr_t?”. Ich werde versuchen, das “Wofür kann es verwendet werden?” Teil in diesem Beitrag.

Hauptsächlich für bitweise Operationen an Zeigern. Denken Sie daran, dass man in C++ keine bitweisen Operationen mit Zeigern durchführen kann. Gründe finden Sie unter Warum können Sie in C keine bitweisen Operationen mit dem Zeiger ausführen, und gibt es eine Möglichkeit, dies zu umgehen?

Um also bitweise Operationen an Zeigern durchzuführen, müsste man Zeiger auf den Typ uintptr_t umwandeln und dann bitweise Operationen durchführen.

Hier ist ein Beispiel für eine Funktion, die ich gerade geschrieben habe, um bitweise exklusive oder 2 Zeiger zum Speichern in einer XOR-verknüpften Liste auszuführen, sodass wir in beide Richtungen wie eine doppelt verknüpfte Liste durchlaufen können, jedoch ohne die Strafe, 2 Zeiger in jedem Knoten zu speichern .

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

1647123016 558 Was ist der Datentyp uintptr t
bd2357

Auf die Gefahr hin, ein weiteres Nekromanten-Abzeichen zu bekommen, möchte ich eine sehr gute Verwendung für hinzufügen uintptr_t (oder auch intptr_t) und das ist das Schreiben von testbarem eingebettetem Code.

Ich schreibe hauptsächlich eingebetteten Code, der auf verschiedene Arm- und derzeit Tensilica-Prozessoren abzielt. Diese haben verschiedene native Busbreiten und die Tensilica ist eigentlich eine Harvard-Architektur mit separaten Code- und Datenbussen, die unterschiedliche Breiten haben können.

Ich verwende für einen Großteil meines Codes einen testgetriebenen Entwicklungsstil, was bedeutet, dass ich Komponententests für alle von mir geschriebenen Codeeinheiten durchführe. Das Testen von Einheiten auf tatsächlicher Zielhardware ist mühsam, daher schreibe ich normalerweise alles auf einem Intel-basierten PC entweder unter Windows oder Linux mit Ceedling und GCC.

Allerdings beinhaltet ein Großteil des eingebetteten Codes Bit-Twiddling und Adressmanipulationen. Die meisten meiner Intel-Rechner sind 64-Bit. Wenn Sie also Adressmanipulationscode testen möchten, benötigen Sie ein verallgemeinertes Objekt, mit dem Sie Berechnungen durchführen können. Und so kam es dass der uintptr_t geben Ihnen eine maschinenunabhängige Möglichkeit, Ihren Code zu debuggen, bevor Sie versuchen, ihn auf Zielhardware bereitzustellen.

Ein weiteres Problem besteht darin, dass bei einigen Maschinen oder sogar Speichermodellen bei einigen Compilern Funktionszeiger und Datenzeiger unterschiedliche Breiten haben. Auf diesen Maschinen erlaubt der Compiler möglicherweise nicht einmal das Umwandeln zwischen den beiden Klassen, aber uintptr_t sollte beides halten können.

— Bearbeiten —

Wurde von @chux darauf hingewiesen, dass dies nicht Teil des Standards ist und Funktionen keine Objekte in C sind. Es funktioniert jedoch normalerweise und da viele Leute diese Typen nicht einmal kennen, hinterlasse ich normalerweise einen Kommentar, der den Trick erklärt. Andere Suchen in SO weiter uintptr_t wird weitere Erläuterungen liefern. Außerdem machen wir Dinge in Unit-Tests, die wir in der Produktion niemals machen würden, weil es gut ist, Dinge kaputt zu machen.

  • Nicht sicher, ob relevant … Haben Sie “opaque typedefs” ausprobiert? Video: youtube.com/watch?v=jLdSjh8oqmE

    – shcha

    1. April 2020 um 0:24 Uhr


  • @sleske Ich wünschte, das wäre in C verfügbar. Aber stdint.h zu haben ist besser als nichts. (Wünschen Sie auch Aufzählungen, bei denen stärker getippt wird, aber die meisten Debugger leisten gute Arbeit, um sie auf jeden Fall herauszufinden.)

    – bd2357

    13. Mai 2020 um 23:31 Uhr

  • “aber uintptr_t sollte beides halten können.” –> Nicht ganz. uintptr_t gut zu konvertieren in/von a void * und void * zu/von _object-Zeigern. Ein Funktionszeiger darf nicht mit a umlaufen void *– (zB Funktionszeiger größer als void *) und passen somit nicht in a uintptr_t.

    – chux – Wiedereinsetzung von Monica

    1. Juli 2020 um 17:43 Uhr

  • @chux, ja, das ist in einigen begrenzten Fällen nicht portierbar. Werde eine Anmerkung hinzufügen. Es ist viele Jahre her, dass ich mir Intel-16-Bit-Sachen angesehen habe, aber Segmente machen die Dinge durcheinander.

    – bd2357

    3. Juli 2020 um 18:22 Uhr

  • Nicht sicher, ob relevant … Haben Sie “opaque typedefs” ausprobiert? Video: youtube.com/watch?v=jLdSjh8oqmE

    – shcha

    1. April 2020 um 0:24 Uhr


  • @sleske Ich wünschte, das wäre in C verfügbar. Aber stdint.h zu haben ist besser als nichts. (Wünschen Sie auch Aufzählungen, bei denen stärker getippt wird, aber die meisten Debugger leisten gute Arbeit, um sie auf jeden Fall herauszufinden.)

    – bd2357

    13. Mai 2020 um 23:31 Uhr

  • “aber uintptr_t sollte beides halten können.” –> Nicht ganz. uintptr_t gut zu konvertieren in/von a void * und void * zu/von _object-Zeigern. Ein Funktionszeiger darf nicht mit a umlaufen void *– (zB Funktionszeiger größer als void *) und passen somit nicht in a uintptr_t.

    – chux – Wiedereinsetzung von Monica

    1. Juli 2020 um 17:43 Uhr

  • @chux, ja, das ist in einigen begrenzten Fällen nicht portierbar. Werde eine Anmerkung hinzufügen. Es ist viele Jahre her, dass ich mir Intel-16-Bit-Sachen angesehen habe, aber Segmente machen die Dinge durcheinander.

    – bd2357

    3. Juli 2020 um 18:22 Uhr

995300cookie-checkWas ist der Datentyp uintptr_t?

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

Privacy policy