2010-04-21 14 views
13

Quiero copiar una matriz int a otra matriz int. Usan la misma definición de longitud para que siempre tengan la misma longitud.memcpy(), ¿cuál debería ser el valor del parámetro de tamaño?

¿Cuáles son las ventajas y desventajas de las siguientes dos alternativas del parámetro de tamaño para memcpy()?

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

o

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

¿La segunda opción siempre funciona? Independientemente del contenido?

Una cosa que favorece a la última es que si la matriz fuera a cambiar, será algo de mantenimiento para actualizar los memcpy() 's.

Gracias

+0

Depende enteramente de cómo haya declarado 'dst' (y hasta cierto punto, si' src' es igual o mayor que 'dst'). – dreamlax

Respuesta

22

Mientras dst está declarada como una matriz con un tamaño, sizeof devolverá el tamaño de esa matriz en bytes:

int dst[ARRAY_LENGTH]; 

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

Si dst sólo pasa a ser un puntero al primer elemento de dicha una array (que es del mismo tipo que la matriz en sí), no lo puedo trabajar:

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

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

sizeof(dst) sólo es correcto si dst es una matriz que tamaño es conocido en tiempo de compilación: como int arr[ARRAY_LENGTH] o una matriz de longitud variable C99; de lo contrario, devuelve el tamaño de un puntero, no la longitud de la matriz de destino.

Para evitar futuros errores, sea coherente y prefiera la primera forma: tamaño de tipo * longitud.

+0

¿De verdad? Hice int arr [10]; cout << sizeof (arr) << endl; para obtener 40 que sospecho que no es el valor del puntero. – Tomas

+0

No si 'dst' es una matriz. – dreamlax

+1

Depende si dst es puntero o matriz "real". –

1

Suponiendo que dst es del tipo int *, sizeof (dst) devolverá el tamaño del puntero (es decir, 4 en un sistema de 32 bits, 8 en un sistema de 64 bits), por lo que su segundo ejemplo solo copiará esto muchos bytes, mientras que el primero usará correctamente el tamaño real del contenido.

2

Si ha asignado usando malloc debe indicar el tamaño de la matriz

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

Si ha asignado con una matriz estática que sólo puede utilizar sizeof

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

Será el segundo la opción siempre funciona? Independientemente del contenido?

La segunda opción sólo funciona si se ha añadido posterior al ) falta y dst es una matriz estática (es decir, del tipo int[123]).

Si dst tiene tamaño desconocido (es decir int[]), entonces sizeof dst sólo devuelve el tamaño del puntero, ya que dst ha decaído a un puntero. En este caso, debe usar sizeof(*dst)*ARRAY_LENGTH.

+0

+1, pero no creo que "estático" sea el término correcto para una variable del tipo de matriz.Podría ser un sistema automático, y "estático" ya tiene muchos significados en C y especialmente en C++. Tu "ie" es más parecido. –

1

¿la segunda opción siempre funciona? Independientemente del contenido?

Funcionará sólo si ambas condiciones se cumplen:

  • dst es matriz regular, no PUNTERO
  • src y dst son del mismo tamaño
+0

O 'src' es más grande que' dst'. – dreamlax

0

Depende. Tanto arr como pointer son matrices, pero sizeof() solo devuelve el tamaño correcto para arr, que se declara en tiempo de compilación.

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

No se olvide de las matrices de longitud variable C99. Su longitud se determina en tiempo de ejecución pero 'sizeof' seguirá funcionando. – dreamlax

0

Si se asignó dst del montón (utilizando malloc, por ejemplo), la segunda solución no funcionará. sizeof (dst) solo funcionará cuando se lo sepa al compilador. Por ejemplo, el siguiente ejemplo fallará como sizeof (dst) será igual a la sizeof un puntero (4-8 bytes.)

#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 

Este segmento de código trabajará cada vez:

#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

Si y cuando tienes una matriz (real) puedes usar el truco sizeof(array), pero ten en cuenta que si refactorizas el código y lo desplazas a algún lugar donde la matriz se haya descompuesto en un puntero (o si la memoria se asignó inicialmente en un puntero malloc/nuevo) necesitará pasar un tamaño conocido.

Ignorando los tamaños relativos de origen y destino, es decir, suponiendo que son los mismos para el resto de la discusión, si está utilizando C++ recomendaría un truco de metaprogramación que le dará un conteo de tamaño seguro para matrices y fallará para compilar si intenta usarlo con punteros:

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

de esa manera:

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 
} 

Si en algún momento usted refactoriza y el código se traslada a un lugar en el que la matriz ha decaído (o reemplazar una matriz estática para una asignada dinámicamente) el compilador le dirá que debe corregir el cálculo de tamaño.

+0

¡Ni siquiera noté que la pregunta estaba etiquetada 'C++', +1! – dreamlax

+1

muy agradable, pero solo 'return sizeof a;' es suficiente. –

+0

@BenVoigt: Corregir (y corregir) –

-1

¿Qué tal?

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

Esto debería funcionar incluso si el tamaño de los elementos individuales era menor que el tamaño tomado por cada elemento en la matriz real.

+1

No tengo claro las circunstancias en las que crees que funcionará, pero el formulario original no. –

+0

@Dennis: Tienes razón, probablemente estaba pensando en 'struct's desempaquetar, donde elementos sucesivos pueden no seguirse inmediatamente ... En C arrays, puedes asumir que' & a [n + 1] = = & a [n] + sizeof (a [0]) ', o' & a [n] == a + n * sizeof (a [0]) ', por lo que la forma original funcionará bien. Perdón por la confusion. – squelart

+0

Esto no funcionará sin un 'sizeof', o un molde a' char * '. –

1

sizeof (X) siempre le da el número de bytes de "X" si X es una matriz uint16_t de 10, a continuación, sizeof (X) devolverá 20

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

$> sizeof x: 20 

si desea que el número de elementos que tienen que hacer un poco de aritmética de bytes:
8 bits = 1 byte
16 bits = 2 bytes
32 bits = 4 bytes
64 bits = 8 bytes

así que para obtener el número de elementos que podrían hacer:

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

lo que resulta en:

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

, por supuesto, es probable que desee hacer (sizeof (X)/sizeof (X [0])) una constante/variable de modo que usted no calcula cada vez ... (No sé si los compiladores siempre optimizarán esto)

0

memcpy(), ¿cuál debería ser el valor del parámetro de tamaño?

Debe ser el mínimo entre el tamaño del búfer fuente y el tamaño del búfer de destino.

Tradicionalmente, se ha usado el tamaño del buffer fuente. Eso desbordó el búfer de destino en ocasiones ... Por lo tanto, es mejor usar una versión de la función "más segura": una que especifique los tamaños de búfer de origen y de destino.

Tiene funciones "más seguras" disponibles a través del ISO/IEC TR24731. Hay mucho más que eso, como valores de retorno consistentes y un comportamiento consistente de manejo de cadenas.

Las funciones "más seguras" ahora forman parte del estándar C, por lo que se supone que debe estar disponible en todas partes. Por lo tanto, debe usar memcpy_s.

No puede usarlo en Linux, ya que no proporciona las funciones (no crea que el marketing publicitario sobre estándares cumple). En Linux, debe "lanzar su propio contenedor".

No todo el mundo es fanático de las funciones más seguras. Ver, por ejemplo, Do you use the TR 24731 'safe' functions?. Sobre todo lo que puedo decir sobre eso es: Multiple libunp buffer overflows. Millones de enrutadores y puertas de enlace están sujetos a múltiples vulnerabilidades y muchos permanecen sin parchear. Y se debieron a errores que habrían sido detenidos por las funciones más seguras. +1 a todos los que dicen "no usen esta basura de Microsoft".

Cuestiones relacionadas