8 Stimmen

c89: Umwandlung eines int in void* und zurück

Zunächst einmal ist dies kein Duplikat von:

Ist es sicher, eine int zu void Zeiger und zurück zu int wieder?

Der Unterschied in den Fragen ist folgender: Ich verwende den void* nur, um den int zu speichern, aber ich verwende ihn eigentlich nie als void*.

Die Frage läuft also auf Folgendes hinaus:

Ist ein void * garantiert mindestens so breit wie ein int

Ich kann intptr_t nicht verwenden, weil ich c89 / ANSI C verwende.

EDITAR

In stdint.h von C99 (gcc-Version) sehe ich Folgendes:

/* Types for `void *' pointers.  */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int        intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned long int   uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int         intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned int        uintptr_t;
#endif

Könnte ich möglicherweise einfach etwas Ähnliches zusammenbasteln und erwarten, dass es funktioniert? Es scheint, dass das Casting funktionieren sollte, da alle intptr_t ist ein typedef zu einem integralen Typ ...

9voto

Oliver Charlesworth Punkte 259497

Nein, dies ist nicht garantiert sicher.

In der C99-Norm heißt es dazu (Abschnitt 6.3.2.3):

Eine Ganzzahl kann in einen beliebigen Zeigertyp umgewandelt werden. Sofern nicht anders angegeben, ist das Ergebnis ist implementierungsabhängig, ist möglicherweise nicht korrekt ausgerichtet und zeigt möglicherweise nicht auf eine Entität des referenzierten Typs zeigen und kann eine Trap-Darstellung sein.

Jeder Zeigertyp kann in einen Integer-Typ konvertiert werden. Sofern nicht anders angegeben, ist das Ergebnis ist implementierungsabhängig. Wenn das Ergebnis nicht im Integer-Typ dargestellt werden kann, ist das Verhalten undefiniert. Das Ergebnis muss nicht im Wertebereich eines beliebigen Integer Typs liegen.

Ich bin ziemlich zuversichtlich, dass die Zeit vor C99 nicht anders sein wird.

2voto

Wayne Taylor Punkte 51

FreeRTOS speichert Timer-IDs in Timer_t als void* pvTimerID. Wenn man diese also als Speicherplatz und NICHT als Zeiger auf etwas verwendet, muss man sie in etwas umwandeln, das z.B. als Array-Index verwendet werden kann.

um die id zu lesen, die als void* gespeichert ist:

void* pvId = pxTimer->pvTimerID; int index = (int)(pvId - NULL);

1voto

cnicutar Punkte 173420

Es gibt eine C FAQ: Kann ich eine ganze Zahl vorübergehend in einen Zeiger stecken oder umgekehrt? .

Die sauberste Antwort ist: Nein, das ist nicht sicher, vermeiden Sie es und machen Sie weiter. Aber POSIX dies möglich sein muss. Es ist also ist sicher auf POSIX-kompatiblen Systemen.

1voto

Hier ist eine tragbare Alternative.

static const char dummy[MAX_VALUE_NEEDED];
void *p = (void *)(dummy+i); /* cast to remove the const qualifier */
int i = p-dummy;

Natürlich kann es untragbar große Mengen an virtuellem Adressraum verschwenden, wenn Sie große Werte benötigen, aber wenn Sie nur kleine Integer-Werte übergeben wollen, ist es ein 100% portabler und sauberer Weg, Integer-Werte in void * .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X