Warum/wann `intptr_t` für die Typumwandlung in C verwenden?
Lesezeit: 7 Minuten
william_grisaitis
Ich habe eine Frage zur Verwendung intptr_t vs. long int. Ich habe beobachtet, dass sich das Inkrementieren von Speicheradressen (z. B. über manuelle Zeigerarithmetik) je nach Datentyp unterscheidet. Zum Beispiel fügt das Erhöhen eines char-Zeigers 1 zur Speicheradresse hinzu, während das Erhöhen eines int-Zeigers 4, 8 für ein Double, 16 für ein langes Double usw. hinzufügt.
was gut kompiliert und ausgeführt wurde, aber XCode gab mir Warnungen für meine Typumwandlung: “Vom Zeiger in eine Ganzzahl unterschiedlicher Größe umwandeln.”
Nach einigem Googeln und Bingen (ist letzteres schon ein Wort?) sah ich, dass einige Leute die Verwendung empfahlen intptr_t:
was die Fehler tatsächlich behebt. Also dachte ich, von jetzt an sollte ich verwenden intptr_t für Typumwandlungszeiger … Aber dann, nach einigem Herumzappeln, fand ich heraus, dass ich das Problem lösen konnte, indem ich einfach ersetzte int mit long int:
printf( "pChar: %ld\n", ( long int )pChar );
printf( "pFloat: %ld\n", ( long int )pFloat );
Meine Frage ist also, warum intptr_t nützlich, und wann sollte es verwendet werden? Es scheint in diesem Fall überflüssig. Klar, die Speicheradressen für myChar und myFloat waren einfach zu groß, um in einen zu passen int… also typisieren sie sie long ints hat das Problem gelöst.
Liegt es daran, dass Speicheradressen manchmal zu groß sind? long int auch? Jetzt, wo ich darüber nachdenke, denke ich, dass dies möglich ist, wenn Sie > 4 GB RAM haben. In diesem Fall könnten Speicheradressen 2 ^ 32 – 1 überschreiten (Maximalwert für vorzeichenlose lange Ints …), aber C wurde lange davor erstellt war vorstellbar, oder? Oder waren sie so vorausschauend?
Vielen Dank!
Ja, Binging ist ein Wort, das ursprünglich bedeutete, sich einer Aktivität, insbesondere dem Essen, bis zum Exzess hinzugeben.
– Ack
4. Juli 2014 um 17:13 Uhr
Verwenden intptr_t mit den printf-Funktionen ist nicht portierbar, es gibt keinen Formatbezeichner dafür. Wandeln Sie den Zeiger stattdessen in einen void-Zeiger um und verwenden Sie die %p Formatbezeichner.
– osven
19. November 2017 um 13:52 Uhr
intptr_t ist eine neue Erfindung, die geschaffen wurde, nachdem 64-Bit- und sogar 128-Bit-Speicheradressen vorgestellt wurden.
Wenn du je müssen einen Zeiger in einen Integer-Typ umwandeln, stets verwenden intptr_t. Alles andere verursacht unnötige Probleme für Personen, die Ihren Code in Zukunft portieren müssen.
Es hat lange gedauert, alle Fehler damit in Programmen wie Mozilla/Firefox auszubügeln, wenn Leute es auf 64-Bit-Linux kompilieren wollten.
Es wäre besser zu verwenden uintptr_t. Signierte Typen sind chaotisch und machen mit Zeigern sicherlich keinen Sinn …
– R.. GitHub HÖR AUF, EIS ZU HELFEN
13. Juni 2011 um 5:10 Uhr
Guter Anruf. Alles, worüber ich geschrieben sehe uintptr_t ist im Kontext von c++ und der inttypes.h Bibliothek. sieht aus als wäre es drin stdint.h, allerdings auch. jede Differenz?
– william_grisaitis
13. Juni 2011 um 5:30 Uhr
Apropos stets verwenden intptr_t Diese Antwort behauptet, dass sie nicht allgemein verfügbar ist stackoverflow.com/a/9492910/1073672 . Was also tun?
– Benutzer10607
23. Dezember 2014 um 7:11 Uhr
@ user10607: Es ist ab C99 verfügbar. Das ist mehr als ein Jahrzehnt. Es sei denn, Sie verwenden einen alten Compiler wie TurboC oder eine sehr exotische Plattform ohne die Absicht, einen Zeiger zu halten Wille verfügbar sein 😉
– MestreLion
17. Februar 2015 um 6:13 Uhr
@MestreLion das stimmt nicht, es ist optional in C99
– osven
19. November 2017 um 13:46 Uhr
Hier ist die Sache: Auf einigen Plattformen int hat die richtige Größe, aber bei anderen long hat die richtige Größe. Woher wissen Sie, welches Sie verwenden sollten? Du nicht. Man könnte Recht haben, aber der Standard gibt keine Garantie dafür, welches es wäre (wenn es eines von beiden ist). Der Standard bietet also einen Typ, der die richtige Größe hat, unabhängig davon, auf welcher Plattform Sie sich befinden. Wo man vorher schreiben musste:
#ifdef PLATFORM_A
typedef long intptr;
#else
typedef int intptr;
#endif
Jetzt schreibst du einfach:
#include <stdint.h>
Und es deckt so viele weitere Fälle ab. Stellen Sie sich vor, Sie spezialisieren das obige Snippet auf jede einzelne Plattform Ihr Code läuft weiter.
Hm, danke für die Klarstellung. Was wäre, wenn Sie gerade verwendet haben long die ganze Zeit? Würde nicht long auch mit kürzeren Adressen arbeiten? Funktioniert die zusätzliche Speicherzuweisung für longs vs ints die Leistung erheblich beeinträchtigen?
– william_grisaitis
13. Juni 2011 um 4:22 Uhr
@caravaggisto – Nein. long ist nur garantiert 32 Bit und funktioniert möglicherweise nicht auf einer 64-Bit-Plattform. Könntest du immer gebrauchen long long, aber das existiert nicht vor C99. Ich bezweifle, dass die Zuordnung viel ausmacht. Es ist eher ein Problem der Korrektheit.
– Chris Lutz
13. Juni 2011 um 4:27 Uhr
Ich wäre sehr skeptisch gegenüber jedem C-Buch, das Ihnen beibringt, zwischen Zeigern und ganzen Zahlen umzuwandeln. Eigentlich weisen fast alle Casts auf Bugs hin; Sie sind zumindest ein Code-Geruch. Pointer/Integer-Casts sind viel schlimmer.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
13. Juni 2011 um 5:12 Uhr
@R..: Häufig hat eine API, die eine Rückruffunktion bereitstellt, oder eine Messaging-API wie die Windows-Nachrichtenpumpe ein oder zwei ganzzahlige Datenfelder, die weitergegeben werden können. Ihr Programm muss möglicherweise einen Zeiger in a einfügen DWORD oder ein int denn das ist alles, was in der API verfügbar ist.
– Zan Luchs
5. September 2012 um 15:41 Uhr
@ZanLynx WinAPI ist eine schreckliche API, die Mitte der 80er Jahre für schrecklich kaputte Pre-Standard-C-Compiler entwickelt wurde. Es hat sich seit der Win16-Ära nicht viel geändert. Es gibt einen Grund, warum MS versucht, es zu töten.
– Jonathan Baldwin
10. März 2014 um 22:28 Uhr
Zuerst, intptr_t ist nur für Datenzeiger (keine Funktionen) und ist nicht garantiert vorhanden.
Dann, nein, Sie sollten es nicht zum Drucken verwenden. Das %p ist dafür. Sie müssen nur Ihren Zeiger auf werfen (void*) und los gehts.
Es ist auch nicht gut für die Arithmetik / den Zugriff auf einzelne Bytes. Cast zu (unsigned char*) stattdessen.
intptr_t ist wirklich für die seltenen Fälle, in denen Sie Zeiger als ganze Zahlen interpretieren müssen (was sie wirklich nicht sind). Tun Sie das nicht, wenn Sie nicht müssen.
Danke. Was sind denn Zeiger, wenn nicht (binäre) ganze Zahlen? Vielen Dank für Ihre Zeit.
– william_grisaitis
14. Juni 2011 um 16:57 Uhr
@caravaggisto, das hängt stark von der Architektur ab. Einige Architekturen haben einen segmentierten Speicher, sodass eine Adresse aus zwei Teilen besteht. Nur eine einfache Integer-Addition ergibt beispielsweise nicht immer eine gültige Adresse. Arithmetik an unsigned char reicht aus, vorausgesetzt, Sie haben einen Chunk zugewiesen, der groß genug ist.
– Jens Gustedt
14. Juni 2011 um 18:17 Uhr
intptr_t oder uintptr_t könnte für bestimmte Szenarien nützlich sein. Zum Beispiel bauen Sie Ihre eigene Version von malloc()B. ein spezialisierter dynamischer Speicherzuordner, vielleicht für ein eingebettetes System oder ein anderes Computersystem, wo ein spezialisierter Speicherzuordner benötigt wird. Angenommen, Sie behalten den Überblick über freigegebene Blöcke in einer expliziten frei verknüpften Liste. Sie könnten ein intptr_t verwenden, um Zeiger auf die nächsten und vorherigen Blöcke in der verknüpften Liste zu speichern. Dies wäre nicht Teil der Nutzlast selbst, sondern das vorherige Wort davor in einer “Kopfzeile” oder “Fußzeile” des Blocks.
– Galaxie
4. Juli 2018 um 22:42 Uhr
Sie könnten Ihr Leben einfacher machen, indem Sie die verwenden p Konvertierungsbezeichner:
printf("%p\n", (void *)foo);
Auch die portable Möglichkeit, eine Variable vom Typ zu drucken (u)intptr_t ist die zu verwenden PRI*PTR Makros aus inttypes.h; Folgendes entspricht der Verwendung p auf meiner Plattform (32-Bit):
Ja, Binging ist ein Wort, das ursprünglich bedeutete, sich einer Aktivität, insbesondere dem Essen, bis zum Exzess hinzugeben.
– Ack
4. Juli 2014 um 17:13 Uhr
Verwenden
intptr_t
mit den printf-Funktionen ist nicht portierbar, es gibt keinen Formatbezeichner dafür. Wandeln Sie den Zeiger stattdessen in einen void-Zeiger um und verwenden Sie die%p
Formatbezeichner.– osven
19. November 2017 um 13:52 Uhr