2010-04-21 8 views
13

Voglio copiare un array int su un altro array int. Usano la stessa definizione per la lunghezza in modo che siano sempre della stessa lunghezza.memcpy(), quale dovrebbe essere il valore del parametro size?

Quali sono i pro/contro delle seguenti due alternative del parametro size a memcpy()?

memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); 

o

memcpy(dst, src, sizeof(dst)); 

Sarà la seconda opzione funziona sempre? Indipendentemente dal contenuto?

Una cosa che favorisce l'ultima è che se l'array dovesse cambiare, sarà un po 'di housekeeping aggiornare i memcpy().

Grazie

+0

Dipende interamente da come è stato dichiarato 'dst' (e in una certa misura, anche se' src' è uguale o maggiore di 'dst'). – dreamlax

risposta

22

Fintanto dst viene dichiarata come array di dimensioni, sizeof restituirà la dimensione di tale matrice in byte:

int dst[ARRAY_LENGTH]; 

memcpy(dst, src, sizeof(dst)); // Good, sizeof(dst) returns sizeof(int) * ARRAY_LENGTH 

Se dst solo sembra essere un puntatore al primo elemento di un tale array (che è dello stesso tipo della matrice stessa), non funzionerà:

int buffer[ARRAY_LENGTH]; 
int* dst = &buffer[0]; 

memcpy(dst, src, sizeof(dst)); // Bad, sizeof(dst) returns sizeof(int*) 
5

sizeof(dst) è corretta solo se dst è una matrice quale formato è noto al momento della compilazione: come int arr[ARRAY_LENGTH] o una matrice di lunghezza variabile C99; altrimenti restituisce la dimensione di un puntatore, non la lunghezza della matrice di destinazione.

Per evitare futuri bug, essere coerenti e preferire la prima forma: dimensione del tipo * lunghezza.

+0

Davvero? Ho fatto int arr [10]; cout << sizeof (arr) << endl; ottenere 40 che sospetto non sia il valore del puntatore. – Tomas

+0

Non se 'dst' è un array. – dreamlax

+1

Dipende se dst è puntatore o array "reale". –

1

Supponendo che dst sia di tipo int *, sizeof (dst) restituirà la dimensione del puntatore stesso (cioè 4 su un sistema a 32 bit, 8 su un sistema a 64 bit), quindi il secondo esempio riguarderà solo ogni copia di questo molti byte, mentre il primo utilizzerà correttamente la dimensione effettiva del contenuto.

2

Se è stato assegnato utilizzando malloc è necessario indicare la dimensione della matrice

int * src = malloc(ARRAY_LENGTH*sizeof(*src)); 
int * dst1 = malloc(ARRAY_LENGTH*sizeof(*dst)); 
memcpy(dst1,src,ARRAY_LENGTH*sizeof(*dst)); 

Se è stato assegnato con un array statico si può semplicemente utilizzare sizeof

int dst2[ARRAY_LENGTH]; 
memcpy(dst2,src,sizeof(dst2)); 
3

Sarà la seconda l'opzione funziona sempre? Indipendentemente dal contenuto?

La seconda opzione funziona solo se si è aggiunto di nuovo i dispersi )edst è un array statico (cioè di tipo int[123]).

Se dst ha dimensioni sconosciute (cioè int[]), quindi sizeof dst restituisce solo la dimensione del puntatore, dal momento che è stato dst decaduto a un puntatore. In questo caso, è necessario utilizzare sizeof(*dst)*ARRAY_LENGTH.

+0

+1, ma non penso che "statico" sia il termine corretto per una variabile di tipo array.Potrebbe essere un automatico, e "statico" ha già molti significati in C e specialmente in C++. Il tuo "ie" è più simile. –

1

disposta la seconda opzione funziona sempre? Indipendentemente dal contenuto?

Esso funziona solo se entrambe le condizioni sono soddisfatte:

  • dst è matrice regolare, non mostrato nel cursore
  • src e dst hanno le stesse dimensioni
+0

Oppure 'src' è più grande di' dst'. – dreamlax

0

Dipende. Sia arr che pointer sono matrici, ma sizeof() restituisce solo la dimensione corretta per arr, che viene dichiarata al momento della compilazione.

int main() { 
     int arr[10]; 
     int * pointer; 
     pointer = (int *) malloc(10 * sizeof(int)); 
     printf("%d\n", sizeof(arr)); // 40 
     printf("%d\n", sizeof(pointer)); // 4 or 8 
     free(pointer); 
} 
+0

Non dimenticare gli array di lunghezza variabile C99. La loro lunghezza è determinata in fase di esecuzione ma 'sizeof' funzionerà ancora. – dreamlax

0

Se dst è stato allocato dall'heap (utilizzando malloc ad esempio), la seconda soluzione non funzionerà. sizeof (dst) funzionerà solo quando è noto al compilatore. Ad esempio, il seguente esempio fallirà come sizeof (dst) sarà uguale alla sizeof un puntatore (4-8 byte.)

#define ARRAY_LENGTH 10 
int *dst; 

dst = malloc(ARRAY_LENGTH*sizeof(int)); 
memcpy(dst, src, sizeof(dst)); // sizeof dst in this case would be 4 bytes on 32 bit system 

Questo segmento di codice funziona ogni volta:

#define ARRAY_LENGTH 10 
int *dst; 

dst = malloc(ARRAY_LENGTH*sizeof(int)); 
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes 
5

Se e quando si dispone di un array (quello reale), è possibile utilizzare il trucco sizeof(array), ma si noti che se si rifatta il codice e lo si inserisce in un punto in cui l'array è decaduto in un puntatore (o se inizialmente la memoria era allocata in un puntatore (malloc/new) sarà necessario superare una dimensione nota

Ignorando le dimensioni relative di origine e destinazione, ovvero supponendo che siano uguali per il resto della discussione, se si utilizza C++, consiglierei un trucco metaprogrammante che fornirà un conteggio delle dimensioni tipicamente corretto per gli array e non riuscirà per compilare se si tenta di utilizzarlo con i puntatori:

template <typename T, int N> 
inline int array_memory_size(T (&a)[N]) { return sizeof a; } 

questo modo:

int main() { 
    int array[10]; 
    int *ptr = array; 
    int orig[10] = { 0 }; 
    memcpy(array, orig, array_memory_size(array)); // ok 
    //memcpy(ptr, orig, array_memory_size(ptr)); // compilation error 
} 

Se in qualsiasi momento si refactoring e il codice si sposta in un luogo in cui la matrice è decaduto (o si sostituisce un array statico per uno assegnato dinamicamente) il compilatore ti dirà che è necessario correggere il calcolo delle dimensioni.

+0

Non ho nemmeno notato che la domanda era codificata 'C++', +1! – dreamlax

+1

molto bello, ma è sufficiente "return sizeof a;". –

+0

@BenVoigt: corretto (e corretto) –

-1

Che ne dici?

memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]); 

Questo dovrebbe funzionare anche se la dimensione dei singoli elementi è inferiore alla dimensione assorbita da ogni elemento dell'array reale.

+1

Non sono chiaro su quali circostanze pensi che funzioni, ma la forma originale non lo farebbe. –

+0

@Dennis: hai ragione, probabilmente stavo pensando a 'struct's decompressi, dove gli elementi successivi potrebbero non seguirsi immediatamente ... In array C, puoi assumere che' & a [n + 1] = = & a [n] + sizeof (a [0]) ', o' & a [n] == a + n * sizeof (a [0]) ', quindi il modulo originale funzionerà perfettamente. Dispiace per la confusione. – squelart

+0

Questo non funzionerà senza 'sizeof', o un cast su' char * '. –

1

sizeof (X) si dà sempre il numero di byte di "X" se X è una matrice uint16_t di 10, quindi sizeof (X) restituirà 20

uint16_t X[10]={0}; 
cout<<"sizeof x: "<<sizeof(X); 

$> sizeof x: 20 

se si desidera che il numero di elementi che hanno a che fare un po 'di aritmetica di byte:
8bit = 1byte
16bit = 2bytes
32bit = 4 byte
64bit = 8 byte

in modo da ottenere il numero di elementi che potrebbero fare:

numb_of_elements = (sizeof(X)/sizeof(X[0])); 

conseguente:

uint32_t source[100]={0}; 
memcpy((void*) dest, (void*) source, (sizeof(source)/sizeof(source[0]))); 

naturalmente probabilmente si vorrebbe fare (sizeof (X)/sizeof (X [0])) una costante/variabile in modo che non calcoliamo ogni volta .. (Non so se i compilatori lo ottimizzeranno sempre)

0

memcpy(), quale dovrebbe essere il valore del parametro size?

Dovrebbe essere il minimo tra la dimensione del buffer di origine e la dimensione del buffer di destinazione.

Tradizionalmente, è stata utilizzata la dimensione del buffer di origine. A volte il buffer di destinazione è stato sovraccaricato ... Quindi è meglio usare una versione "più sicura" della funzione: quella che specifica sia le dimensioni del buffer di origine che di destinazione.

Sono disponibili funzioni "più sicure" tramite ISO/IEC TR24731. C'è molto di più, come valori di ritorno coerenti e comportamento costante di gestione delle stringhe.

Le funzioni "più sicure" fanno ora parte dello standard C, quindi dovrebbe essere disponibile ovunque. Quindi dovresti usare memcpy_s.

Non è possibile utilizzarlo su Linux, perché non fornisce le funzioni (non credere al clamore di marketing sugli standard conformi)). Su Linux, dovresti "arrotolare il tuo" wrapper.

Non tutti sono fan delle funzioni più sicure. Vedi, ad esempio, Do you use the TR 24731 'safe' functions?. Tutto quello che posso dire a riguardo è: Multiple libunp buffer overflows. Milioni di router e gateway sono soggetti a vulnerabilità multiple e molti rimangono privi di patch. Ed erano dovuti a bug che sarebbero stati fermati dalle funzioni più sicure. +1 a tutti quelli che stanno dicendo "non usare questa merda di Microsoft".