Domanda

Piuttosto che l'invio di un puntatore reale per un valore, il valore è gettato a un puntatore. Ho trovato questi esempi nel codice interfaccia grafica di un programma GTK.

g_signal_connect (pastebutton[pane],
                  "clicked",
                  G_CALLBACK(on_paste_button_pressed),
                  (void*)((long)pane<<4));

Nell'esempio di cui sopra, mi riferisco a l'ultimo parametro di g_signal_connect. Quando on_paste_button_pressed è chiamato da GTK2, on_paste_button_pressed getta il puntatore user_data vuoto indietro in questo modo:

int pane = ((long)user_data) >> 4;

In realtà, ho aggiunto questo particolare esempio per il codice, ma ho basato su di ciò che era già lì. Ho aggiunto il bit-shifting in modo da evitare gli avvertimenti sulla fusione. Il programma stesso è dotato di quattro riquadri che contengono un certo numero di widget, i pulsanti di copia e incolla consentono di copiare tutti i valori da un riquadro all'altro.

È questo il modo di lanciare un valore a un indirizzo di puntatore spesso usato, e non ci sono ragioni per cui questo non dovrebbe essere utilizzato?

modifica

Il cast da un numero intero a un puntatore nullo può anche essere ottenuta in questo modo:

void* void_ptr = some_int - NULL;
È stato utile?

Soluzione

È utilizzato . Si tratta di utilizzato abbastanza comunemente quando si fa ciò che è necessario.

Una ragione per non usarlo è che le dimensioni teoricamente puntatore potrebbe essere più piccola della dimensione intero sorgente.

Un altro motivo per non usarlo è che permette di passare solo un pezzo di dati interi al callback. Se in futuro sarà necessario aggiungere un altro pezzo di dati (o passare a un non intero), dovrete localizzare e riscrivere ogni singolo posto in cui la richiamata rende l'accesso ai dati passati. Quindi, se c'è una possibilità che avrebbe dovuto estendere i dati in futuro, è meglio creare un struct (anche se si tiene una sola int in questo momento) e passare un puntatore a tale struct.

Ma se si è certi che non dovrete mai passare qualcosa di diverso da quel singolo intero e che il vostro intero si inserisce in un void *, allora questa tecnica non è in alcun modo rotto.

PS pedantescamente parlando, né C né C ++ sembrano avere la garanzia di andata e ritorno per intero a vuoto conversione * -per intero, cioè non garantiscono che funzionerà e ripristinare la originale valore integrale.

Altri suggerimenti

Si dovrebbe usare le macro GINT_TO_POINTER () e GPOINTER_TO_INT () per lanciare tra i puntatori e interi.

glib: Tipo conversione macro

Casting un intero a un puntatore viene utilizzato per passare un valore per valore. Questo è il modo preferito se avete bisogno di un parametro per riferimento perché il compilatore quindi non ha bisogno di dereference il puntatore.

Il bit-shifting è una cattiva idea, perché può causare overflow.

Per il codice realmente portatile, è necessario utilizzare intptr_t come tipo integer causa sarà ben inserirsi in un puntatore.

Non vede l'uso in questo tipo di casi, sì. Funziona su molte piattaforme, ma può non riuscire perché un intero arbitrario non è sempre un valore puntatore valido, anche se il cambio si fa dovrebbe ottenere intorno a quello. E 'anche possibile che un puntatore non può contenere tutti i valori che un numero intero può; questo sarebbe il caso se si sta utilizzando un 64-bit long su una piattaforma in cui i puntatori sono 32 bit, e, naturalmente, dal momento che si sta spostando il valore, potrebbe anche non riuscire anche se puntatori e interi sono le stesse dimensioni. Se si desidera utilizzare questo trucco, si dovrebbe probabilmente verificare sizeof (void*) contro la dimensione del tipo integer si usa, e al momento del check fase di esecuzione contro il valore reale se il puntatore non è abbastanza grande. E 'probabilmente non vale la pena di fare questo completamente portatile in modo che si usa un puntatore reale su piattaforme in cui ciò che è necessario, quindi o limitatevi a piattaforme in cui questo trucco funziona o abbandonare del tutto il trucco.

Lo trovo bene. Non hai statistiche relative alla frequenza di utilizzo, ma non si interessa davvero?

Non sono sicuro di aver capito come po-shifting aiuta, però.

E 'utilizzato, ma è affatto portatile in modo da stare attenti.

Lo standard C non mandato che i tipi di puntatore hanno almeno tanti bit come tipi interi, quindi potrebbe non essere sempre in grado di farlo.

Ma io non riesco a ricordare qualsiasi piattaforma in cui i puntatori hanno effettivamente stato più piccolo di numeri interi in modo da siete probabilmente sicuro (pur non essendo tecnicamente sicuri).

L'unico motivo che posso pensare che il casting può essere lì per è quello di rimuovere la possibilità di avvertimenti di allineamento. Sezione 6.3.2.3 del progetto di stati C1X:

  

Un numero intero può essere convertito in qualsiasi tipo di puntatore. Salvo quanto precedentemente specificato, la   risultato dipende dall'implementazione, potrebbe non essere allineata correttamente, non potrebbe puntare a un   entità del tipo indicato, e potrebbe essere una rappresentazione trappola.

Questo è dal C-FAQ:

D: Come sono interi convertiti da e puntatori? Posso roba temporaneamente un intero in un puntatore, o viceversa?

A: C'era una volta, è stato garantito che un puntatore potrebbe essere convertito in un numero intero (anche se non si sa mai se un int o un long potrebbe essere necessario), e che un intero potrebbe essere convertito in un puntatore, e che un puntatore è rimasta invariata quando convertito in un numero intero (abbastanza grande) e viceversa, e che le conversioni (e qualsiasi mappatura) erano destinati ad essere `` sorprendente per chi conosce la struttura di indirizzamento della macchina. '' In altre parole , c'è qualche precedente e supporta elaborazione interi / puntatore, ma sono sempre stati dipendente dalla macchina, e quindi non portabile. sono sempre stati necessari cast espliciti (anche se i primi compilatori raramente si lamentavano se li avete lasciati fuori).

L'ANSI / ISO C standard, al fine di garantire che C è ampiamente implementabile, ha indebolito le garanzie precedenti. Pointer-to-integer e integer-to-pointer conversioni sono definiti dall'implementazione (vedi discussione 11.33), e non v'è più alcuna garanzia che i puntatori possono essere convertiti in numeri interi e schiena, senza cambiamenti.

Forzare puntatori in numeri interi o interi in puntatori, non è mai stata buona pratica. Quando avete bisogno di uno slot generico che può contenere entrambi i tipi di dati, un sindacato è un'idea molto migliore.

vedere anche domande 4.15, 5.18 e 19.25.

Riferimenti: K & R1 Sez. A14.4 p. 210 K e R2 Sez. A6.6 p. 199 ISO Sez. 6.3.4 Sec Razionale. 3.3.4 H & S Sez. 6.2.3 pag. 170, Sez. 6.2.7 pp. 171-2

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top