Richtige format-Bezeichner zu drucken Zeiger oder die Adresse?
Dem Formatbezeichner sollte ich verwenden, um drucken Sie die Adresse einer Variablen? Ich bin verwirrt zwischen den unten viel.
%u unsigned integer
%x hexadezimale Wert
%p - void-Zeiger
Was wäre das optimale format zum drucken einer Adresse?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die einfachste Antwort, vorausgesetzt, Sie nichts dagegen haben, den Launen und Schwankungen im format zwischen verschiedenen Plattformen, ist die standard -
%p
notation.Den C99-standard (ISO/IEC 9899:1999) sagt in §7.19.6.1 ¶8:
(In C11 — ISO/IEC 9899:2011 — die information ist in §7.21.6.1 ¶8.)
Auf einigen Plattformen, umfassen, eine führende
0x
und auf andere nicht, und die Buchstaben werden könnte, in Kleinbuchstaben oder Großbuchstaben, und der C-standard gar nicht definiert, es wird hexadezimal ausgegeben, obwohl ich weiß, keine Umsetzung, wo es nicht ist.Ist es etwas fraglich, ob Sie explizit konvertieren Sie die Zeiger mit einer
(void *)
Stimmen. Es wird explizit, was in der Regel gut (so ist es, was ich Tue), und der standard sagt: "das argument ist ein Zeiger aufvoid
'. Auf den meisten Maschinen, die Sie erhalten würden, mit weglassen einer expliziten cast. Aber es wäre die Sache auf einem Computer, auf dem die bit-Darstellung eineschar *
- Adresse für einen Speicherbereich unterscheidet sich von der 'alles andere Zeiger' Adresse für den gleichen Speicherbereich. Das wäre ein Wort-adressiert sind, statt der byte-adressiert, Maschine. Solche Maschinen sind nicht üblich (wahrscheinlich nicht vorhanden) in diesen Tagen, aber der erste Rechner an dem ich gearbeitet habe nach der Uni war eine solche (ICL Perq).Wenn Sie nicht zufrieden mit der Implementierung-definiert das Verhalten von
%p
, dann verwenden Sie C99<inttypes.h>
unduintptr_t
statt:Dies ermöglicht Ihnen die Feinabstimmung der Darstellung an sich anzupassen. Ich entschied mich für die hex-Ziffern in der oberen Fall, so dass die Zahl ist einheitlich die gleiche Höhe und die charakteristische dip am Anfang der
0xA1B2CDEF
erscheint somit, nicht wie0xa1b2cdef
die dips oben und unten entlang der Reihe zu. Ihre Wahl, obwohl, innerhalb sehr weiter Grenzen. Die(uintptr_t)
cast ist eindeutig empfohlen von GCC, wenn es Lesen kann der format-string zur compile-Zeit. Ich denke, es ist richtig, auf Anfrage die-cast, aber ich bin mir sicher, es gibt einige, die würde die Warnung ignorieren und Weg mit ihm die meiste Zeit.Kerrek fragt in den Kommentaren:
War ich unter der illusion, dass der C-standard sagt, dass alle Objekt-Pointer muss die gleiche Größe haben, so
void *
undint *
können verschiedene Größen. Jedoch, was ich denke, ist der entsprechende Abschnitt der C99-standard ist nicht so emphatischen (obwohl ich nicht weiß, von einer Implementierung, wo das, was ich vorgeschlagen wahr ist, ist eigentlich falsch):(C11, sagt genau das gleiche in den §6.2.5, ¶28 und Fußnote 48.)
So, alle Zeiger auf Strukturen muss die gleiche Größe wie jedes andere und müssen die gleiche Ausrichtung Anforderungen, auch wenn die Strukturen, die die Zeiger zeigen auf möglicherweise unterschiedliche alignment-Anforderungen. Ähnlich wie für die Gewerkschaften. Zeichen Zeiger und void-Pointer muss die gleiche Größe und Ausrichtung Anforderungen. Zeiger auf Variationen
int
(Bedeutungunsigned int
undsigned int
) müssen die gleiche Größe und Ausrichtung Anforderungen wie jede andere; auch für andere Arten. Aber der C-standard nicht offiziell sagen, dasssizeof(int *) == sizeof(void *)
. Tja, SO ist dafür gut, um Sie überprüfen Sie Ihre Annahmen.C-standard definitiv nicht erforderlich-Funktion-Zeiger auf die gleiche Größe, die als Objekt-Zeigern. Das war notwendig, nicht brechen die verschiedenen Speicher Modelle auf DOS-artige Systeme. Dort konnte man mit 16-bit-Daten-Zeiger, aber für 32-bit-Funktionszeiger-oder Umgekehrt. Dies ist der Grund, warum der C-standard nicht Mandat, dass Funktionszeiger konvertiert werden kann Objektzeiger und Umgekehrt.
Glücklicherweise (für die Programmierer, welche auf POSIX), POSIX-Schritte in die Bresche und übernimmt das Mandat, die Funktion Zeiger und Daten Zeiger haben die gleiche Größe:
So, es scheint, dass explizite casts zu
void *
sind sehr zu empfehlen für maximale Zuverlässigkeit in den code bei der übergabe eines Zeigers auf eine Variable Funktion wieprintf()
. Auf POSIX-Systemen, es ist sicher zu werfen Sie einen Funktionszeiger auf eine void-Zeiger für den Druck. Auf anderen Systemen ist es nicht unbedingt sicher, das zu tun, noch ist es unbedingt sicher zu übergeben von Zeigern andere alsvoid *
ohne cast.void*
? Ansonsten, wennint*
waren, sagen wir, zwei bytes, undvoid*
waren 4 bytes, dann wäre es eindeutig ein Fehler zu Lesen vier Byte von dem argument, nicht?dlsym()
- Funktion statt. Eines Tages werde ich schreiben, bis die änderung...aber 'eines Tages' nicht 'heute'.void *
? Hmm, ich sehe dein Kommentar here. Da nur eine-wat Konvertierung erforderlich ist (Funktion Zeiger aufvoid *
), funktioniert es dann?void *
und zurück, ohne Verlust von Informationen. Pragmatisch gesehen, gibt es sehr wenige Maschinen, bei denen die Größe einer Funktion ein Zeiger ist nicht das gleiche wie die Größe der ein Zeiger auf ein Objekt. Ich glaube nicht, dass der standard stellt eine Methode zum drucken ein Funktionszeiger auf Maschinen, wo tha Umstellung ist problematisch.printf("%p\n", (void *)funcptr);
aber es ist wirklich nicht klar, dass es dabei hilft, mehr alsprintf("%d\n", (int)longvalue);
ist sicher nützlich, wennsizeo(int) != sizeof(long)
und der Wert inlongvalue
ist größer als passt in einint
.#include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); }
ist es ein Undefiniertes Verhalten drucken-Adresse der Variablen, die mit%u
Formatbezeichner ? Adresse der Variablen in den meisten Fällen positiv ist, so kann ich%u
statt%p
?%u
aber Ihre Zeiger 64 bit. Ja, es ist undefiniert. Wenn Sie drucken möchten, den Mauszeiger mit integer-Formate, verwenden einige variation auf PRIXPTR wie gezeigt in meiner Antwort.char *
. Stimmt, vor allem auf PCs, auf denen es "weit" - Zeiger.%p
kam in weit verbreiteten Einsatz mit dem C89/C90-standard. Es gibt viele andere Funktionen, die nicht in der ursprünglichen Standard-I/O-Bibliothek von 1978 oder so ungefähr (vielleicht ein paar Jahre früher als das), aber diese Fragen sind selten relevant, niemanden mehr. Wenn Sie ein Thema sind, ist der Programmierer in der Regel bewusst, welche Unterlagen gilt. In diesen Umgebungen, gibt es nichtlong long
oderuintptr_t
oder ... entweder. Viele Dinge, die anders waren, in der pre-Geschichte von C.p
ist der umwandlungsspezifikator drucken Zeiger. Verwenden Sie dieses.Denken Sie daran, dass das weglassen der cast ist Undefiniertes Verhalten und das drucken mit
p
umwandlungsspezifikator erfolgt in eine von der Implementierung definierte Art und Weise.Verwenden
%p
für "Zeiger", und benutze nichts sonst*. Sie sind nicht garantiert der standard, dass Sie erlaubt werden, um zu behandeln, einen Zeiger wie jede Besondere Art von integer, also würden Sie tatsächlich ein Undefiniertes Verhalten mit der integrierten Formate. (Zum Beispiel%u
erwartet eineunsigned int
, aber was ist, wennvoid*
hat eine andere Größe oder Ausrichtung-Anforderung alsunsigned int
?)*) [Siehe Jonathan feine Antwort!] Alternativ zu
%p
Sie kann Verwendung Zeiger-spezifische Makros aus<inttypes.h>
, Hinzugefügt in C99.Alle Objekt-Pointer sind implizit konvertierbar
void*
in C, aber um zu übergeben den Zeiger als variadic argument, Sie haben zu werfen es explizit (da beliebige Objekt-Pointer sind nur Cabrio, aber nicht identisch zu void-Zeigern):void *
(obwohlprintf()
Sie technisch müssen die expliziten cast, da es eine Variable Funktion). Funktionszeiger sind nicht unbedingt Cabrio zuvoid *
.void *
- und zurück-Funktion Zeiger ohne Verlust; zum Glück, obwohl, POSIX nicht explizit verlangen, dass (Feststellung, dass es nicht Teil von standard-C). So, in der Praxis, Sie können mit ihm Weg erhalten (Umwandlungvoid (*function)(void)
zuvoid *
und zurückvoid (*function)(void)
), aber streng ist es nicht zwingend durch den C-standard.%u
!%u
. Würde ich entfernen Sie den Satz "streng genommen", obwohl. IMO es verweist auf das Problem der Domäne der Sprache der Juristen, wenn es tatsächlich eine ernsthafte real-Welt-bug verwenden die falsche Bezeichner.%u
und%lu
sind falsch auf einigen Maschinen, und dass%p
ist viel besser als jeder von denen. Es gibt jedoch zwei integer-Typen, die Sie verwenden können, zuverlässig -intptr_t
unduintptr_t
(obwohl, warum würden Sie wollen, verwendet die signierte version, ich bin mir nicht sicher!). Siehe meine Antwort. Ja, ja - was Sie sagen, ist meistens gut. (Ich habe entfernt, was ich als der umstrittene Teil des Austauschs mit @R..).<inttypes.h>
Makros... in der Tat, würdig der Kapitel von selbst!%u
und%lu
sind falsch auf alle Maschinen, nicht einige Maschinen. Die Spezifikationprintf
ist sehr klar, dass, wenn die übergebenen entspricht nicht dem erforderlichen Typ der Formatbezeichner, ist das Verhalten undefiniert. Ob die Größe der Arten entspricht (und das kann true oder false sein, je nach Maschine) ist irrelevant; es sind die Typen, die übereinstimmen müssen, und Sie werden es nie.#include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); }
ist es ein Undefiniertes Verhalten drucken-Adresse der Variablen, die mit %u Formatbezeichner ? Adresse der Variablen in den meisten Fällen positiv ist, so kann ich%u
statt%p
?unsigned int
, und übergeben Sie eineint *
, so ist es UB.Als eine alternative zu den anderen (sehr guten) Antworten, Sie werfen könnte, um
uintptr_t
oderintptr_t
(ausstdint.h
/inttypes.h
) und verwenden Sie die entsprechende integer-umwandlungsspezifikationen. Dies würde es ermöglichen mehr Flexibilität in, wie die Zeiger formatiert ist, aber streng genommen um eine Umsetzung ist nicht verpflichtet, diese Typdefinitionen.uintptr_t
.#include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); }
ist es ein Undefiniertes Verhalten drucken-Adresse der Variablen, die mit%u
Formatbezeichner ? Adresse der Variablen in den meisten Fällen positiv ist, so kann ich%u
statt%p
?%u
ist ein format fürunsigned int
Typ und kann nicht verwendet werden, die mit einem Zeiger-argument zuprintf
.