Ist es eine gute Idee zu verwenden intptr_t
als Allzweckspeicher (zum Halten von Zeigern und ganzzahligen Werten) statt void*
? (Wie hier zu sehen: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html)
Denn was ich schon gelesen habe:
int
-> void*
-> int
Hin- und Rückfahrt ist nicht garantiert, den ursprünglichen Wert beizubehalten; ich vermute int
-> intptr_t
-> int
Wird besorgt
- Zeigerarithmetik auf beiden
void*
und intptr_t
erfordert Würfe, also bekommt hier keiner einen Vorteil
void*
bedeutet weniger explizite Umwandlungen beim Speichern von Zeigern, intptr_t
bedeutet weniger Casts beim Speichern von Integer-Werten
intptr_t
erfordert C99
Was muss ich noch beachten?
Ist es eine gute Idee zu verwenden intptr_t
als Allzweckspeicher (zum Halten von Zeigern und ganzzahligen Werten) statt void*
?
Nein.
intptr_t
ist nicht garantiert vorhanden. Erstens wurde es, wie Sie bemerken, in C99 eingeführt. Zweitens müssen Implementierungen keinen ganzzahligen Typ haben, der groß genug ist, um konvertierte Zeigerwerte ohne Informationsverlust zu halten.
Konvertieren ein int
zu intptr_t
und zurück ist unwahrscheinlich Informationen zu verlieren, aber dafür gibt es keine wirkliche Garantie intptr_t
ist breiter als int
.
Wenn Sie Zeigerwerte speichern möchten, speichern Sie sie in Zeigerobjekten. Dafür sind Zeigerobjekte da.
Jeder Zeiger auf ein Objekt oder einen unvollständigen Typ kann konvertiert werden void*
und wieder zurück ohne Informationsverlust. Es gibt keine solche Garantie für Zeiger auf Funktionen – aber jeder Zeiger-auf-Funktion-Typ kann ohne Informationsverlust in jeden anderen Zeiger-auf-Funktion-Typ und zurück konvertiert werden. (Ich beziehe mich auf den C-Standard; ich denke, POSIX bietet einige zusätzliche Garantien.)
Wenn Sie entweder eine Ganzzahl oder einen Zeigerwert im selben Objekt speichern möchten, sollten Sie als Erstes Ihr Design überdenken. Wenn Sie dies bereits getan haben und zu dem Schluss gekommen sind, dass Sie dies wirklich tun möchten, sollten Sie die Verwendung einer Union in Betracht ziehen (und sorgfältig verfolgen, welche Art von Wert Sie zuletzt gespeichert haben).
Es gibt APIs, die a verwenden void*
Argument, um die Übergabe beliebiger Daten zu ermöglichen; siehe zum Beispiel die POSIX pthread_create()
Funktion. Dies kann missbraucht werden, indem ein ganzzahliger Wert an gecastet wird void*
aber es ist sicherer, die zu passieren die Anschrift eines Integer-Objekts.
Nein, es kann nicht garantiert werden, dass ein bestimmter Typ sowohl Zeiger als auch ganze Zahlen vernünftig speichern kann, und außerdem macht es Ihren Code unübersichtlich. Es gibt einen besseren Weg.
Wenn Sie eine Ganzzahl und einen Zeiger im selben Objekt speichern möchten, besteht die saubere und portable Methode darin, eine Union zu verwenden:
union foo {
int integer_foo;
void *pointer_foo;
};
Dies ist tragbar und ermöglicht es Ihnen, beide Arten von Dingen in der Größe des Speichers aufzubewahren, die für den größeren der beiden erforderlich ist. Es funktioniert garantiert immer.
Nein. (Wenn es so wäre, hätten sie einfach die Semantik von intptr_t hinzugefügt
void*
)– Billy ONeal
29. Februar 2012 um 2:34 Uhr
Der Beitrag fragt “(to hold pointers and integer values)”, diskutiert dann aber nur
int
,void *
undintptr_t
. Wieuintmax_t
,size_t
,long long
etc. sind auch Integer-Typen, klingt so, als ob es bei der Frage nur um Objektzeiger geht,intptr_t
undint
Typen.– chux – Wiedereinsetzung von Monica
28. Januar 2016 um 23:11 Uhr