Ich habe mir angesehen Fortgeschrittene Linux-Programmierung von Mitchell, Oldham und Samuel. Ich habe im Abschnitt über pthreads etwas über void-Zeiger und Casting gesehen, das mich verwirrt.
Wenn sie ein Argument an pthread_create() übergeben, wandeln sie den Zeiger nicht in einen void-Zeiger um, obwohl die Funktion dies erwartet.
Aber wenn sie einen Wert nehmen, der vom Thread mit pthread_join zurückgegeben wird, wandeln sie die Variable in einen void-Zeiger um.
pthread_join( thread, (void*) &prime );
Hier, prim ist vom Typ int wieder.
Warum wird in zweiter Instanz gegossen und nicht in erster Instanz?
pthread_joinDas zweite Argument von ist eine Leere**. Dieser Code sieht falsch aus.
– Johannes Zwinck
9. Dezember 2013 um 11:54 Uhr
Betrachtet man den vollständigen Code (advancedlinuxprogramming.com/alp-folder/alp-ch04-threads.pdf) zeigt, dass das Beispiel die void* von der Thread-Funktion zurückgegeben und von empfangen pthread_join() wie int. Dies ist die relevante Zeile von compute_prime(): int candidate; ... return (void*) candidate; Also verwenden &prime als 2. argument zu int prime; ... pthread_join(..., &prime) macht absolut Sinn. Aber casr es zu void* ist einfach falsch. Wenn ein Gips angelegt wird void** gültig gewesen wäre, wie durch die Erklärung von pthread_join(pthread_t, void **).
– alk
4. Januar 2014 um 13:53 Uhr
alk
Es ist nicht erforderlich, von oder zu einem Zeiger auf umzuwandeln void in C:
6.3.2.3 Zeiger
1 Ein Zeiger auf Leere kann in oder von einem Zeiger auf einen beliebigen unvollständigen oder Objekttyp konvertiert werden. Ein Zeiger auf einen beliebigen unvollständigen oder Objekttyp kann in einen Zeiger auf umgewandelt werden Leere
und wieder zurück; das Ergebnis soll mit dem ursprünglichen Zeiger verglichen werden.
Die einzigen Ausnahmen hiervon sind
beim Drucken eines Zeigers mit der "%p" Konvertierungsbezeichner, da er nur für definiert ist void *.
beim Kopieren des Werts eines Zeigers aus einer intptr_t oder uintptr_t zurück zu a void *.
“beim Drucken eines Zeigers mit dem Konvertierungsbezeichner “%p”, da er nur für void * definiert ist” – Ich drucke oft nicht void* Zeiger verwenden %p und es scheint zu funktionieren. Ist es einfach nicht tragbar? Soll ich die Zeiger auf werfen void*?
– Aviv Cohn
24. November 2019 um 12:40 Uhr
@AvivCohn: “Soll ich die Zeiger werfen” Um kompatibel zu bleiben, ja, das sollten Sie, sonst wird ein undefiniertes Verhalten aufgerufen, das dazu führen kann, dass (scheinbar) funktioniert oder abstürzt oder ….
– alk
24. November 2019 um 13:14 Uhr
Fred Fu
Das zweite Beispiel ist ein gutes Beispiel dafür, warum Casting auf void* ist meistens ein fehler. Es sollte sein
void *primep = ′ // no cast needed
pthread_join(thread, &primep);
Weil pthread_join nimmt ein void** als zweites Argument. Das void* stellt nur sicher, dass der Fehler den Compiler passiert, weil die void* umgewandelt wird void** automatisch.
Also, wann tun Sie müssen zu werfen void* oder zurück:
beim Arbeiten mit Zeigern, die als ganze Zahlen gespeichert sind ((u)intptr_t);
beim Übergeben von Zeigern auf Funktionen, die einen unvollständigen Prototyp und einen unvollständigen Take haben void* (Oder nehmen Sie einen anderen Zeigertyp und Sie haben void*); das bedeutet normalerweise Funktionen, die eine variable Anzahl von Argumenten annehmen, wie z printf.
Das void** Parameter von pthread_join ist ein Out-Parameter. Es macht keinen Sinn, primep zu initialisieren. Sein Wert wird ignoriert und überschrieben.
– n. 1.8e9-wo-ist-meine-Aktie m.
23. September 2018 um 6:15 Uhr
In C, Umwandlung in void* von jedem Zeigertyp und umgekehrt erfolgt implizit. Die Besetzung im zweiten Beispiel ist nicht erforderlich.
(Beachten Sie, dass beim C++-Casting jeder Zeiger auf void* ebenfalls implizit erfolgt (mit Ausnahme von Funktionszeigern und Funktionsmember-/Methodenzeigern, die nicht auf void* gecastet werden können), aber das Casting erfordert ein explizites Casting.)
int pthread_join(pthread_t thread, void **retval);
Also, die pthread_join nimmt ein pointer to void* als zweites Argument. Das ist weil,
In pthread_join erhalten Sie die Adresse zurück, die der fertige Thread an pthread_exit übergeben hat. Wenn Sie nur einen einfachen Zeiger übergeben, wird er als Wert übergeben, sodass Sie nicht ändern können, wohin er zeigt. Um den Wert des an pthread_join übergebenen Zeigers ändern zu können, muss dieser selbst als Zeiger übergeben werden, also als Zeiger auf einen Zeiger.
Nun zu deiner Frage: „Warum wird in zweiter Instanz gegossen und nicht in erster Instanz?„In erster Linie, dh pthread_createes erwartet a void* als viertes Argument. Also vorbei &which_prime würde implizit konvertiert werden void*.
Im zweiten Fall, dh pthread_joines erwartet a void** und wir gehen vorbei &prime dort. Der Compiler wird sich also beschweren. Um den Fehler zu umgehen, übergibt der Autor also eine Besetzung von void* die automatisch konvertiert werden void**.
Aber das ist keine gute Lösung.
Die Lösung::
void* prime ; // make prime as void*
pthread_join( thread, &prime );
printf( "%" PRIxPTR "\n", (intptr_t)prime ) ;
// intptr_t instead of int to get an integer type
// that's the same size as a pointer
Ich glaube, auf den gleichen Code wurde in anderen Fragen verwiesen.
Die Antwort im zweiten Link erklärt:
Es ist nicht gültig. Es funktioniert einfach, wenn sizeof(int) == sizeof(void *), was auf vielen Systemen vorkommt.
Ein void * kann nur garantiert Zeiger auf Datenobjekte enthalten.
Hier ist eine C-FAQ zu diesem Thema.
Und der zitierte Text:
Wie werden Ganzzahlen in und von Zeigern konvertiert? Kann ich vorübergehend eine Ganzzahl in einen Zeiger stecken oder umgekehrt?
Zeiger-zu-Ganzzahl- und Ganzzahl-zu-Zeiger-Konvertierungen sind implementierungsdefiniert (siehe Frage 11.33), und es gibt keine Garantie mehr, dass Zeiger ohne Änderung in Ganzzahlen und zurück konvertiert werden können
Zeiger in ganze Zahlen oder ganze Zahlen in Zeiger zu zwingen, war noch nie eine gute Praxis
In C99 können Zeiger sicher konvertiert werden intptr_t/uintptr_t und zurück.
– Fred Foo
9. Dezember 2013 um 12:30 Uhr
@FredFoo falls vorhanden. Sie sind im Standard optional
– osven
4. April 2018 um 19:33 Uhr
In C99 können Zeiger sicher konvertiert werden intptr_t/uintptr_t und zurück.
– Fred Foo
9. Dezember 2013 um 12:30 Uhr
@FredFoo falls vorhanden. Sie sind im Standard optional
– osven
4. April 2018 um 19:33 Uhr
13676300cookie-checkWann wird ein Casting-Void-Zeiger in C benötigt?yes
pthread_join
Das zweite Argument von ist eine Leere**. Dieser Code sieht falsch aus.– Johannes Zwinck
9. Dezember 2013 um 11:54 Uhr
Betrachtet man den vollständigen Code (advancedlinuxprogramming.com/alp-folder/alp-ch04-threads.pdf) zeigt, dass das Beispiel die
void*
von der Thread-Funktion zurückgegeben und von empfangenpthread_join()
wieint
. Dies ist die relevante Zeile voncompute_prime()
:int candidate; ... return (void*) candidate;
Also verwenden&prime
als 2. argument zuint prime; ... pthread_join(..., &prime)
macht absolut Sinn. Aber casr es zuvoid*
ist einfach falsch. Wenn ein Gips angelegt wirdvoid**
gültig gewesen wäre, wie durch die Erklärung vonpthread_join(pthread_t, void **)
.– alk
4. Januar 2014 um 13:53 Uhr