Was bedeutet es, int in void* umzuwandeln oder umgekehrt?
Lesezeit: 6 Minuten
Matthias
Was bedeutet es, einen ganzzahligen Wert in a umzuwandeln? void* oder umgekehrt aus Gedächtnissicht? Mein Verständnis ist void* ist eine Adresse zu einem Speicherblock unbestimmter Länge.
Das scheint so etwas zu sein, als würde man Äpfel mit Birnen vergleichen.
int myval = 5;
void* ptr = (void*)myval;
printf("%d",(int)ptr);
Mir wurde klar, dass ich den genauen Kontext hätte angeben sollen, wo dies verwendet wird.
int main(int argc, char* argv[]) {
long thread; /* Use long in case of a 64-bit system */
pthread_t* thread_handles;
/* Get number of threads from command line */
if (argc != 2) Usage(argv[0]);
thread_count = strtol(argv[1], NULL, 10);
if (thread_count <= 0 || thread_count > MAX_THREADS) Usage(argv[0]);
thread_handles = malloc (thread_count*sizeof(pthread_t));
for (thread = 0; thread < thread_count; thread++)
pthread_create(&thread_handles[thread], NULL, Hello, (void*) thread);
printf("Hello from the main thread\n");
for (thread = 0; thread < thread_count; thread++)
pthread_join(thread_handles[thread], NULL);
free(thread_handles);
return 0;
} /* main */
/*-------------------------------------------------------------------*/
void *Hello(void* rank) {
long my_rank = (long) rank; /* Use long in case of 64-bit system */
printf("Hello from thread %ld of %d\n", my_rank, thread_count);
return NULL;
} /* Hello */
Dieser Code stammt aus Peter Pachechos Buch über parallele Programmierung.
Es ist sogar noch schlimmer .. – zumindest so, als würde man Äpfel mit Kartoffeln vergleichen
– alk
23. Dezember 2011 um 17:03 Uhr
bobbymcr
Gießen int zu void * ist ziemlich bedeutungslos und sollte nicht getan werden, da Sie versuchen würden, einen Nicht-Zeiger in einen Zeiger umzuwandeln. Zitieren der C99-StandardAbschnitt 6.3.2.3 Punkt 5:
Eine Ganzzahl kann in einen beliebigen Zeigertyp konvertiert werden. Außer wie zuvor angegeben, ist das Ergebnis implementierungsdefiniert, möglicherweise nicht korrekt ausgerichtet, zeigt möglicherweise nicht auf eine Entität des referenzierten Typs und ist möglicherweise eine Trap-Darstellung.
Du könnte gießen int * zu void * (Jeder Zeiger ist konvertierbar in void * den Sie sich wie den “Basistyp” aller Zeiger vorstellen können).
Gießen void * zu int ist nicht portabel und kann je nach verwendeter Plattform völlig falsch sein (z void * vielleicht 64 Bit breit und int dürfen nur 32 Bit sein). Erneut den C99-Standard zitierend, Abschnitt 6.3.2.3 Punkt 6:
Jeder Zeigertyp kann in einen Integer-Typ konvertiert werden. Außer wie zuvor angegeben, ist das Ergebnis implementierungsdefiniert. Wenn das Ergebnis nicht im Integer-Typ dargestellt werden kann, ist das Verhalten undefiniert. Das Ergebnis muss nicht im Wertebereich eines ganzzahligen Typs liegen.
Um dies zu lösen, bieten einige Plattformen uintptr_t Dadurch können Sie einen Zeiger als numerischen Wert mit der richtigen Breite behandeln.
Dieser “beliebige Zeiger ist konvertierbar void *” ist falsch. Es sollte sein “jeder Zeiger auf ein Objekt ist konvertierbar void *“. Casting-Funktionszeiger auf void * verursacht UB.
– 12431234123412341234123
13. Januar 2021 um 13:59 Uhr
Beide void* Zeiger (oder irgendein Zeiger für diese Angelegenheit) und int sind, grob gesagt, Zahlen. Sie können unterschiedliche Bitgrößen haben, aber es ist unwahrscheinlich, dass der Zeiger kleiner als ist int, wodurch die Operation reversibel wird. Natürlich ist es illegal und Sie sollten niemals den Zeiger dereferenzieren, der keinen gültigen Ort hat, auf den er zeigen kann.
Der C-Standard legt fest, dass es möglich sein muss, einen void-Zeiger in einen ganzzahligen Typ umzuwandeln, sodass die Umwandlung des ganzzahligen Typs zurück in einen void-Zeiger denselben Zeiger ergibt. Ich bin mir nicht sicher, ob es erforderlich ist, dass die Konvertierung eines Nullzeigers in eine ganze Zahl den Wert Null ergibt, oder ob nur numerische Literal-Nullen als etwas Besonderes erkannt werden. Bei vielen Implementierungen stellt der ganzzahlige Wert eine Hardwareadresse dar, aber der Standard gibt keine solche Garantie. Es wäre durchaus möglich, dass auf Hardware, die einen speziellen Trap für die Hardwareadresse 0x12345678 enthält, das Konvertieren eines Zeigers in eine Ganzzahl 0x12345678 von der Hardwareadresse subtrahieren würde und das Konvertieren einer Ganzzahl in einen Zeiger 0x12345678 wieder hinzufügen würde (also ein ganzzahliger Wert von Null würde einen Nullzeiger darstellen).
In vielen Fällen, insbesondere bei der Entwicklung für eingebettete Controller, gibt der Compiler-Anbieter explizit an, auf welche Hardwareadresse zugegriffen wird, wenn ein bestimmter ganzzahliger Wert in einen Zeigertyp konvertiert wird. Auf Prozessoren mit einem einzigen linearen Adressraum würde das Konvertieren eines ganzzahligen Werts 0x12345678 in einen Zeiger im Allgemeinen einen Zeiger ergeben, der auf die Adresse 0x12345678 verweist; Das Hardware-Referenzhandbuch würde angeben, ob es an diesem Ort etwas Besonderes gibt. Auf Prozessoren mit “interessanteren” Adressräumen kann es notwendig sein, etwas anderes als die Hardwareadresse als Zeiger zu verwenden. Auf antiken IBM-PC-Computern wurde der Anzeigepuffer beispielsweise auf die Hardwareadresse 0xB8000 abgebildet, aber in den meisten Compilern würde die Adresse als (kurz weit *) 0xB8000000 ausgedrückt werden.
Das ist ganz so, als würde man Äpfel mit Birnen vergleichen. Dieser Code funktioniert nur, weil Sie ihn explizit hin und her übertragen.
Der C-Compiler kopiert nur die Bytes aus dem int in den Bereich für den Zeiger und zurück, genau wie Sie ein char in einem int halten können.
Dies könnte sogar dazu führen, dass Ihre Nummer durcheinander gebracht wird, wenn auf Ihrer Plattform aus irgendeinem Grund ein ‘int’ länger als ein ‘void *’ ist.
Wenn Sie tatsächlich eine Zahl haben möchten, die Sie von Ganzzahlen in Zeiger und zurück umwandeln können, schauen Sie nach intptr_t. Dieser Typ ist eigentlich dafür ausgelegt, sowohl Ganzzahlen als auch Zeiger zu speichern.
fge
Es ist nützlich, einen Zeiger für die Zeigerarithmetik in einen ganzzahligen Typ umwandeln zu können. Zum Beispiel die offsetof() Makro, das den Versatz eines Mitglieds innerhalb einer Struktur berechnet, benötigt diese Art der Konvertierung.
Allerdings muss darauf geachtet werden, dass der dafür verwendete Primitivtyp mit einem Zeiger umgehen kann: Hier ist dies beispielsweise für 64 Linux bei Verwendung von gcc nicht der Fall: void * hat die Größe 8, ein int hat die Größe 4.
was ohne diese Art von Makro- und Zeigerarithmetik einfach nicht machbar wäre. Aber es ist sehr abhängig von der Toolchain.
Womit hat das zu tun offsetof. Ebenfalls, offsetof plattformdefiniert ist, steht es einer Compiler-Implementierung frei, sie so zu implementieren, wie es am besten passt. ZB implementiert gcc dies durch ein Intrinsic.
– Jens Gustedt
23. Dezember 2011 um 21:15 Uhr
Es wäre, als würde man Äpfel mit Birnen vergleichen, wenn man überhaupt versuchen würde, einen Vergleich anzustellen. Aber das gibt es nicht. Grundsätzlich kann in den meisten Architekturen ein int-Zeiger ohne Informationsverlust in einen void-Zeiger umgewandelt werden, und ein void-Zeiger kann auch wieder ohne Informationsverlust in einen int-Zeiger umgewandelt werden. Natürlich sollten Sie nicht versuchen, diesen Zeiger zu dereferenzieren, da er auf keinen sinnvollen Speicherort zeigt: Es ist nur eine Variable, die dasselbe Bitmuster enthält wie das Bitmuster, das die Ganzzahl vor der Umwandlung enthielt.
Womit hat das zu tun offsetof. Ebenfalls, offsetof plattformdefiniert ist, steht es einer Compiler-Implementierung frei, sie so zu implementieren, wie es am besten passt. ZB implementiert gcc dies durch ein Intrinsic.
– Jens Gustedt
23. Dezember 2011 um 21:15 Uhr
13707700cookie-checkWas bedeutet es, int in void* umzuwandeln oder umgekehrt?yes
Mögliches Duplikat von: stackoverflow.com/questions/3568069/…
– Mike Nakis
23. Dezember 2011 um 17:01 Uhr
Es ist sogar noch schlimmer .. – zumindest so, als würde man Äpfel mit Kartoffeln vergleichen
– alk
23. Dezember 2011 um 17:03 Uhr