2009-07-22 23 views
24

Deseo copiar contenido de longitud específica de un búfer a otro desde un punto de partida específico. Revisé memcpy(), pero solo se necesita copiar la longitud del contenido, aunque también quiero especificar el índice de inicio.memcpy con startIndex?

¿Hay alguna función que pueda hacer esto o hay un buen enfoque para hacerlo con la función existente memcpy?

+0

Tenga en cuenta: memcpy es C, no C++. Aunque lo uso con frecuencia, no hay duda de que memcpy en general está en total contraste con los principales conceptos de C++ como tipo de seguridad, herencia, excepciones. etc. Es muy fácil arruinar todo con memcpy. –

+3

memcpy es parte del Estándar C++ –

+0

Claro, en el sentido de que se proporciona a través del encabezado C. Sin embargo, C++ en sí proporciona 'std :: copy', que es _typically_ igual o quizás _ mejor que' memcpy', más mucho más flexible y, de nuevo, seguro para el tipo. –

Respuesta

5

Simplemente agregue el desplazamiento a las direcciones. Por ejemplo, si desea copiar el buffer comenzando con el enésimo byte:

memcpy(destination, source + N, sourceLen - N); 

Esto copiará a la destination. Si también desea compensar el destino, agregue el desplazamiento a ambos:

memcpy(destination + N, source + N, sourceLen - N); 
+1

Esto solo funcionará para los casos en que la fuente apunte a un tipo que tenga 1 byte de longitud. Para todos los demás casos obtendrá un desplazamiento incorrecto (el vacío simplemente no se compilará) – JaredPar

+0

@JaredPar: Es cierto, entonces se requerirá algo más de aritmética. – sharptooth

23

Simplemente agregue el desplazamiento que desea a la dirección del búfer.

char abuff[100], bbuff[100]; 
.... 
memcpy(bbuff, abuff + 5, 10); 

Copia 10 bytes desde abuff [5] a bbuff.

+0

Este es un ejemplo ligeramente engañoso. Solo funciona porque se garantiza que char es de 1 byte de longitud. Para todos los demás tipos donde size <> 1, este código se compilará pero se ejecutará incorrectamente (excepto vacío de valores). – JaredPar

+0

@JaredPar: en mi humilde opinión, la respuesta de Neil es completamente correcta. La pregunta dice "... Quiero especificar el índice inicial". Agregar una constante a un puntero tomará en cuenta el tamaño del tipo que se apunta. Es decir. an 'int * p = ...; p + = 5; ' hará que el punto 'p' sizeof (int) * 5 bytes más. –

+0

char no se menciona en absoluto en la pregunta, sin embargo, el término buffer lo implica levemente – CsTamas

2

No se requiere un índice porque simplemente puede actualizar el puntero de origen en la cantidad de bytes especificada. El siguiente contenedor debería ser el truco

void* memcpy_index(void *s1, const void *s2, size_t index, size_t n) { 
    s2 = ((char*)s2)+index; 
    return memcpy(s1, s2,n); 
} 
+0

está asumiendo que el índice es un índice de bytes yn es un recuento de bytes. En ese caso, s1 y s2 también podrían escribirse char * – Indy9000

+0

@Indeera, la única suposición que estoy haciendo es que el índice, como el campo de tamaño n, se especifica en bytes. – JaredPar

1

Simplemente aumente su puntero al índice de inicio.

Ejemplo

const unsigned char * src = reinterpret_cast<const unsigned char*>(your source); 
unsigned char * dest = reinterpret_cast<unsigned char *>(your dest); 
memcpy(dest, src + offset, len); 

¿Qué pasa con el uso de colecciones STL para evitar errores de acceso a la memoria?

0

Simplemente agregue el índice a la dirección del búfer y páselo a memcpy() como parámetro de origen, p. copia de la 3ª pieza de tampón B

char a[10], b[20]; 
::memcpy(a,b+2,10); 

También tener en cuenta el tipo de elementos de la memoria intermedia, la longitud (tercera) del parámetro de establecimiento de memoria() es en bytes, por lo que la copia 4 enteros pondrás 4 * sizeof (int) - que probablemente será 16 (en un sistema de 32 bits, pero el tipo no importa para la dirección de inicio, debido a la aritmética de punteros:.

int a[10], b[10]; 
::memcpy(a+2, b, 2*sizeof(int)); 
// a+2 will be address of 3rd item in buffer a 
// not address of 1st item + 2 bytes 
51

siempre prefiero la sintaxis

memcpy(&dst[dstIdx], &src[srcIdx], numElementsToCopy * sizeof(Element)); 
+3

Ídem. No puede ser demasiado detallado al copiar memoria a un nivel tan bajo. Nombrar bien sus indicios aumenta la posibilidad de que recuerde exactamente lo que está sucediendo 5 meses después. –

0

Podrías tener un fu nction como a continuación.

template<typename T> 
T* memcopy_index(T* dst,T* src,unsigned int index, unsigned int element_count) 
{ 
    return (T*)memcpy(dst,src + index, element_count * sizeof(T)); 
} 

Puede ser utilizado de la siguiente manera:

int src[]={0,1,2,3,4,5,6}; 
int dst[15]; 

memcopy_index(dst,src,2,5); //copy 5 elements from index 2 

Usted tiene que asegurarse de que el búfer de destino tiene suficiente espacio para copiar los elementos.

0

Si está usando C++, probablemente sea mejor usar std :: copy() en lugar de memcpy(). std :: copy puede tomar punteros con la misma facilidad que los iteradores.

p. Ej.

int src[20]; 
int dst[15]; 

// Copy last 10 elements of src[] to first 10 elements of dst[] 
std::copy(src+10, src+20, dst); 

Al igual que con memcpy(), es su responsabilidad asegurarse de que los punteros sean válidos.

NOTA. Si su uso es crítico para el rendimiento, puede encontrar un memcpy() como se detalla en las otras respuestas más rápido, pero probablemente no mucho.

+1

Su implementación es gratuita para implementar std :: copy utilizando memcpy para objetos antiguos simples. –

+0

Eso es bueno saber. Gracias. +1 –

1

Este sitio necesita una forma de permitir el seguimiento anónimo además de las respuestas anónimas.

¿Por qué, más de una vez, veo esta insensata afirmación de que un "índice" debe estar en unidades de 1 byte? Es todo lo contrario de la convención. Un "índice" suele ser simbólico, una medida cuya compensación de bytes físicos está determinada por el tamaño del elemento en la matriz (o vector, que incluso puede no tener el diseño físico de una matriz, pero entonces memcpy() también es irrelevante de curso).

Así, el 5º elemento en una matriz tiene "índice" 5, pero:

  • Si la matriz es de tipo char, a continuación, el desplazamiento de ese "índice" byte es 5.
  • Si el array es tipo short (en x86), entonces el offset de bytes de ese "índice" es 10.
  • Si la matriz es de tipo int (en x86), el offset de bytes de ese "índice" es 20.
  • Si la matriz es del tipo de algún objeto grande de 48 bytes, entonces el desplazamiento de bytes de ese "índice" es 240.

De qué manera es la forma correcta de acceder a ese elemento específico es un punto lateral. La parte importante es que comprenda la diferencia, elija una y haga que el código sea correcto.


Sobre el significado de las palabras, yo preferiría decir:

void* memcpy_offset(void *s1, const void *s2, size_t offset, size_t n); 

que:

void* memcpy_index(void *s1, const void *s2, size_t index, size_t n); 

encuentro la idea de que un vacío completo genérica * podría tener un "índice "ser engañoso. (Mientras estemos aquí, "dest" y "fuente" o "dentro" y "fuera" serían mucho menos ambiguos que "s1" y "s2". El código no necesita tantos comentarios cuando eliges por sí mismo nombres de variable.)