2016-04-10 16 views
1

Ist es möglich, einen void-Zeiger direkt zu schreiben, ohne einen Fehler zu verursachen? Unten ist ein kleiner Codeschnipsel, den ich aus dem Code here (Beispiel unter Pthread Joining Abschnitt der Seite) extrahiert habe.Typ-casting void * zu lang

{ 
    void *status; 
    long t; 
    rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); 
    rc = pthread_join(thread[t], &status); 
    printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status); 
} 

Wie this manual page sagt, dass pthread_join() kopiert die Exit-Status des Ziel-Thread (dh, dass der Wert der Ziel-Thread zu pthread_exit geliefert()) in die Stelle, auf die durch * RETVAL (* status in dieser Fall). Aber in dem Programm, das ich erwähnt habe, zeigt der Status keinen Ort. Wie kommt es dann, dass das Programm noch funktioniert?

Und zweitens, so weit mein Wissen betrifft, kann der Status keinen langen Wert halten, und dann gibt uns der Typisierungsstatus einen Wert, der lang ist und keine Adresse?

+1

Duplizieren von http: // Stackoverflow .com/questions/12949383/converting-primitive-Datentyp-in-void-Zeiger-Typ? –

+0

@MartinR: Wie [this] (http://man7.org/linux/man-pages/man3/pthread_join.3.html) sagt, dass ** pthread_join() den Exit-Status des Ziel-Threads kopiert (dh der Wert, den der Zielthread an pthread_exit (3)) an den Ort liefert, auf den * retval ** zeigt.Aber in dem Programm, das ich erwähnt habe, verweist _status_ nicht auf irgendeinen Ort. Wie funktioniert das Programm? –

+0

Es funktioniert zufällig. Der Variablenstatus wird nicht initialisiert, so dass er in alle Statuspunkte schreibt. Zufällig kann es irgendwo legal sein. Wenn es irgendwo illegal ist, werden Sie einen Absturz bekommen. – cup

Antwort

1

Schnell Antwort: Nein, verwenden intptr_t

Lange Antwort: lang garantiert nicht ins Leere passen *. Auf einigen Systemen (insbesondere 64-Bit-Intel-Linux-Maschinen) funktioniert es, da void * und long beide 64-Bit-Größen sind und der Intel-Prozessor keine anderen Typenunterschiede aufweist. Auf anderen Maschinen wie 32-Bit Intel Linux wird es nicht funktionieren, seit langem ist 64-Bit und void * 32-Bit auf diesen Rechnern. Exotischere Maschinen haben unterschiedliche Eigenschaften.

Der Standardtyp, der int < -> Zeigerkonvertierungen unterstützt, ist intptr_t, gefunden in stdint.h. Nach dem POSIX Programmierhandbuch:

Der folgende Typ bezeichnet ein signierter Integer-Typ mit der Eigenschaft, dass jeder gültiger Zeiger auf diese Art kann umgewandelt werden ungültig zu erklären, dann in einen Zeiger umgewandelt zurück zu erlöschen, und das Ergebnis vergleicht gleich den ursprünglichen Zeiger: intptr_t

So intptr_t ist ein signierter integer-Typ nicht näher bezeichneter Länge, die garantiert zu unterstützen Umtausch- und * für ungültig zu erklären. Es gibt auch unsignup_t ohne Vorzeichen.

Here is the definition of intptr_t in glibc. Wie Sie sehen können, sind intptr_t und long auf 64-Bit-Rechnern tatsächlich vom selben Typ.

+0

Diese Dokumentation sagt 'intptr_t' kann den Wert eines beliebigen Zeigers enthalten, nicht umgekehrt. Wenn z. B. Zeiger 32-Bit sind und "intptr_t" 64-Bit ist, würde es die Anforderungen erfüllen. (Das heißt, die Umwandlung von Zeiger in Ganzzahl und zurück würde funktionieren.) Ich glaube nicht, dass es einen Typ gibt, der garantiert die entgegengesetzte Eigenschaft hat. – Nemo

+0

Das ist ein guter Punkt, obwohl ich die Glibc-Quelle lese, bin ich zuversichtlich, dass es tatsächlich mit dieser speziellen Implementierung funktionieren würde. Aber ich stimme zu, dass dies vom Standard nicht verlangt wird. Fühlen Sie sich frei, meine Antwort zu klären. – jforberg

0

diese Zeile:

rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); 

ist nicht korrekt.

vorschlagen mit:

rc = pthread_create(&thread[t], &attr, BusyWork, (void *)&t); 

Dann wird das 'Problem'

Hinweis verschwindet: in der Busywork() Funktion den aktuellen Wert zurück von:

long myVar = *parmVoidPtr;