2016-05-11 9 views
6

In un codice C++ che sto leggendo, ho trovato quanto segue. Qualcuno può aiutarmi a capire cosa fanno le seguenti dichiarazioni?Che cosa significa * (int *) (buffer) significa?

char buffer[4096]; 
// some code 
int size = *(int*)(buffer); 
+8

Sai cosa '(int *) buffer' mezzi? Se non si legge su * casting *. Sai cosa fa l'operatore di dereferenziazione unario '*' (ad esempio cosa succede se si ha '* some_pointer')? Se non letto anche su questo. Quindi combina la conoscenza di ogni argomento, come se fossero combinati nell'espressione di cui ti stai interrogando. –

+2

Questa istruzione probabilmente causa anche un'eccezione di allineamento su alcune architetture. – dbrank0

+5

Questa istruzione causa anche un comportamento non definito. – 2501

risposta

6

TL; DR: questo codice è negativo, non pensarci più e andare avanti.


(buffer) questa parentesi significa che il programmatore era insicuro delle proprie capacità di programmazione.

Poiché buffer è un array di caratteri, l'identificatore buffer da solo fornisce un puntatore al primo elemento: un puntatore char.

(int*) Questo è un cast, che converte il puntatore char in un puntatore int.

* prende il contenuto di tale puntatore intero e il risultato viene memorizzato nel numero intero size.

Si prega di notare che questo codice è completamente pericoloso. Molte conversioni di puntatori invocano un comportamento mal definito. Potrebbero esserci problemi di allineamento. Potrebbero esserci problemi di alias del puntatore (Google "strict aliasing rule"). Questo particolare codice è anche dipendente da endianess, il che significa che richiede che il contenuto dell'array di caratteri abbia un determinato ordine di byte.

Nel complesso, non ha senso utilizzare tipi firmati come int o char (magari firmato) quando si eseguono operazioni come questa. In particolare, il tipo char è molto problematico poiché ha una firma definita dall'implementazione e dovrebbe essere evitato. Utilizzare invece unsigned char o uint8_t.

Un po 'meno cattivo codice sarebbe simile a questa:

#include <stdint.h> 

uint8_t buffer[4096]; 
// some code 
uint32_t size = *(uint32_t*)buffer; 
+5

Penso che il tuo codice di esempio non debba usare il trucco del dereferenziatore del puntatore. L'uso di 'memcpy' avrebbe comunque un problema di endianità, ma almeno non ci sarebbe stato UB. – user694733

+0

In che modo il codice ha ancora lo stesso comportamento indefinito meno male? – 2501

+0

@ 2501 Perché non ha i problemi di tipo menzionati. Dimostrare come risolvere quello era lo scopo dello snippet di codice. Per correggere il comportamento indefinito, dovresti fare qualcosa di molto più drastico. – Lundin

1

Si prende l'indirizzo del buffer[0], l'inserisce in un int*, dereferenziazioni che, e utilizza il valore Dereferenced per inizializzare size. In altre parole, prende i primi sizeof(int) byte di buffer, fa finta che quei byte siano un int e memorizza il valore int in size.

+2

Non * direttamente * prende l'indirizzo di 'buffer [0]'. Invece la matrice * decade * a un puntatore al suo primo elemento. –

+1

Non riesco a rinunciare, fino a quando la risposta di risposta spiega anche perché questo codice è rotto e non dovrebbe essere usato. – user694733

14
char buffer[4096];//this is an array of 4096 characters 
// some code 

int size = *(int*)(buffer); 

espressi la (decaduto) puntatore a carattere, che è buffer, ad un puntatore intero. Quindi la dereferisce per ottenere un valore intero . Il valore intero ottenuto da questo sarà composto dai primi 4 valori di carattere dell'array buffer supponendo che la dimensione di int sia 4 byte nella macchina, o che in generale sia composta da sizeof(int) caratteri. In altre parole, la rappresentazione della memoria dei primi caratteri sizeof(int) dell'array buffer verrà trattata come se rappresentassero un singolo valore intero, poiché ora è puntato da un puntatore intero e che verrà memorizzato nel size variabile intera quando il puntatore intero è dereferenziato.

Detto questo, come è stato affermato più volte nella sezione commenti, questo codice non è sicuro. Una cosa che viene in mente è che alcune CPU hanno requisiti di allineamento rigorosi (vedere this answer), e in questo caso non si garantisce che l'indirizzo del primo elemento dell'array buffer sia conforme al requisito di allineamento di un numero intero che risulta non definito operazione in quelle CPU.

Vedere la risposta @Lundin per un motivo in più per cui questo codice non è sicuro e potrebbe non fornirti il ​​risultato che stavi cercando.

+0

@ user694733, true, potrebbe bloccarsi su alcune architetture a causa di un errato allineamento della memoria per un puntatore a 'int' –

+0

@ user694733 Grazie per il tuo feedback, ho cercato di menzionare una ragione che so che si tradurrà in un'operazione non definita su alcune CPU. La risposta di Lundin è più dettagliata sui problemi con questo codice e mi sento come se stessi facendo eco a ciò che è già stato detto. –

3

Qualcuno può aiutarmi a capire che cosa fanno le seguenti dichiarazioni?

La prima affermazione:

char buffer[4096]; 

dichiara un array di chars con dimensioni 4096.

La seconda istruzione:

int size = *(int*)(buffer); 

1. Prima batte il puntatore carattere decaduto all'array buffer (chiamato anche buffer), che è un puntatore che punta al suo primo elemento, fissato al momento della la sua dichiarazione

2. Poi l'inserisce in puntatore a int, o int*

3. Infine, assegna il contenuto di questo puntatore (che sarà di tipo int) alla variabile size.

+0

"prima prende l'indirizzo dell'array' buffer' "è sbagliato, ottenere l'indirizzo di' buffer' sarebbe '& buffer'. Invece 'buffer' * decade a un puntatore * al suo primo elemento. –

+0

@JoachimPileborg ringrazia, ha modificato il mio post! – Marievi

+1

Non riesco a rinunciare, fino a quando la risposta di risposta spiega anche perché questo codice è rotto e non dovrebbe essere usato. – user694733