2010-05-21 22 views
16

(gcc 4.4.4 c89)Cuándo usar strncpy o memmove?

Siempre he usado strncpy para copiar cadenas. Nunca he usado realmente memmove o memcpy mucho. Sin embargo, me pregunto cuándo decidirías si usar strncpy, memmove o memcpy?

El código que estoy escribiendo es para una aplicación cliente/servidor. En la documentación usan bcopy. Sin embargo, ¿podría hacer lo mismo con los demás?

bcopy((char*)server->h_addr, 
     (char*)&serv_addr.sin_addr.s_addr, 
     server->h_length); 

Muchas gracias,

+4

'bcopy' no es una función estándar, que inmediatamente la hace inferior a las estándar. – AnT

Respuesta

20

Nadie contestó todas sus preguntas.

strncpy() se utiliza para copiar datos desde un origen a un dest de un tamaño de conjunto, la copia (relleno) 0x00 s si un byte 0x00 se encuentra en la matriz de origen (cadena) antes del final de la memoria intermedia. A diferencia de strcpy, que copiará felizmente hasta que se encuentre un byte 0, incluso si dicho byte está más allá de su memoria intermedia.

memcpy() se utiliza para copiar desde el origen al destino sin importar los datos de origen. También tiende a ser muy optimizado para hardware y leerá frecuentemente las palabras del sistema (int s/long s) a la vez para acelerar la copia cuando la alineación lo permita.

memmove() se utiliza para copiar desde un área de origen y destino superpuesta (por ejemplo, mover el contenido de una matriz dentro de sí mismo o algo similar, de ahí el movimiento mnemónico). Copia los datos comenzando por la parte posterior en lugar de por delante para evitar que la pérdida de datos de las regiones superpuestas afecte los datos antes de que puedan leerse. También tiende a ser un poco menos eficiente ya que generalmente no hay mucha ayuda de hardware para copiar datos de atrás hacia adelante.

bcopy() y sus familiares (bzero, y algunos otros) es una función de copia de bytes que he visto de vez en cuando en tierra incrustada. Por lo general, copia datos de un byte a la vez desde el origen hasta el destino para evitar problemas en la dirección de la memoria desalineada, aunque cualquier buen memcpy se encargará de esto, por lo que su uso es a menudo sospechoso.

¡Buena suerte!

+4

strncpy no finaliza la copia anticipadamente. strncpy escribe exactamente el número de bytes dado, ya sea copiando el inicio de la cadena solo si es demasiado larga o agregando ceros al final de la copia para llenar el búfer. –

+1

Luego aprendí algo nuevo hoy también. Pensé que terminó temprano. (navega por la red ...) Lookie allí. Cambiando mi explicación arriba ahora :) –

+1

@MichaelDorgan Acabo de tropezar con esto. 'memmove()' no es correcto en tu respuesta. Si la dirección de origen es mayor que la dirección de destino, debe comenzar desde el frente. Si la dirección de origen es más pequeña, debe comenzar desde atrás. –

6

strcpy (y otros métodos str *) dejan cuando se encuentran con un valor NULL (0) bytes. memcpy y las funciones relacionadas NO se detienen cuando encuentran un byte NULL.

Si tiene datos binarios, debe usar memcpy. En su ejemplo, está copiando datos binarios, no datos de cadenas.

strncpy es un caso especial en el que dejará de copiar en un byte NULO, pero aún continuará rellenando la salida con NULL hasta la longitud especificada.

+0

+1, Bastante bien, aunque uno podría argumentar que todos los datos son datos binarios. ;) – WhirlWind

+2

strncpy no deja de llenar el búfer de destino, sin embargo. strncpy escribe exactamente el número de bytes dado, ya sea copiando el inicio de la cadena solo si es demasiado larga o agregando ceros al final de la copia para llenar el búfer. –

+0

Gracias, strncpy clarificado –

4

Utilice strncpy() solo si sabe que hay espacio suficiente para la cadena, porque no garantiza la terminación nula y es demasiado entusiasta si el destino es mucho más corto que la cadena fuente (porque anula la cadena para longitud total). Y si usted sabe la longitud, puede utilizar memmove() ...

Si conoces las longitudes de las cuerdas, memmove() es una buena opción - y nominalmente más rápido que strncpy(), ya que no tiene que comprobar si hay valores nulos, ya que va ; solo copia la cantidad relevante de bytes. (Pretendo memcpy() no existe, ya que puede fallar si las zonas de origen y destino de la superposición de memoria, mientras que memmove() consigan arreglar independientemente.)

Piense en bcopy() como una variante arcaica de los mem*() funciones.

+4

Existe realmente una diferencia entre memcpy (dst, src, size) y memmove (dst, src, size) porque memmove "mueve" la memoria - significa: dst y src pueden superponerse mientras que la superposición debe evitarse al usar memcpy. – Robert

+0

No mencioné 'memcpy()' - Pretendo que no existe. –

+2

'memcpy()' es más barato que 'memmove()' en la mayoría de los casos, ya que generalmente sabe que los almacenamientos intermedios de origen y destino no se superponen. – Hasturkun

5

Si usted no necesita el comportamiento búfer de compilación de la strncpy pero desea que la seguridad de no desbordar el buffer, considere strlcpy

De wikipedia:

strlcpy ofrece dos características que están diseñadas para ayudar a software los desarrolladores evitan problemas La función toma el tamaño del destino como parámetro, evitando desbordamientos de búfer si el parámetro de tamaño es correcto. Si este tamaño es mayor que cero, un byte nulo siempre se escribe en el destino, por lo que la cadena resultante siempre termina en nulo (incluso si la cadena fuente se truncó para ajustarse).

12

Nunca debe utilizar strncpy (a menos que se trate de esa rara situación específica para la que se introdujo). La función no está destinada a ser utilizada con C-strings terminados en cero. El nombre dado a esa función es simplemente un error histórico, y pasa a ser la principal fuente de confusión para las personas que intentan usarlo. strncpy es una función introducida para soportar las llamadas cadenas de "ancho fijo", cadenas no terminadas en cero. Usar strncpy con cadenas terminadas en cero es una mala práctica de programación, aunque puede convertirlo en algo parecido a "funcionar" para ese propósito.

No existe una función para la copia de cadenas "seguras" de longitud limitada en la biblioteca C, aunque algunas implementaciones la proporcionan con el nombre strlcpy, que ya se convirtió en un nombre estándar de facto para esta función. Si su implementación no proporciona strlcpy, impleméntela usted mismo.

Además, es cierto que en muchos casos puede reemplazar la función str... con las funciones mem..., es decir, cuando conoce el número exacto de caracteres para copiar.

+0

¿Seguro? En mi opinión 'strncpy' no tiene nada que ver con cadenas de ancho fijo, el único problema es que' strncpy' no termina en cero la cadena objetivo, si la cadena fuente es mayor que el tamaño dado (que es la fuente de confusión ...). – Frunsi

+0

@frunsi: Absolutamente seguro. La historia de 'strncpy' es bien conocida y está bien documentada. No hay lugar para ningún "IMHO" aquí. La función fue creada para llenar campos de nombre de archivo largos de 14 caracteres en una versión arcaica del sistema de archivos Unix. Ese es el único rol para el que fue utilizado significativamente y ese es el único papel para el que es bueno. – AnT

+0

Tiene dos problemas: 1) no termina en cero si la fuente es larga, 2) se llena con ceros al final del búfer si la fuente es corta. Ambos son suspiros obvios e inmediatos de cadenas de ancho fijo, por supuesto. – AnT

2

Si usted está buscando una manera segura/rápido para copiar, he estado contento con la siguiente técnica:

memcpy(dest, src, sizeof (dest)); 
dest[sizeof(dest) - 1] = '\0';  // ensure null termination 

menos eficiente, pero también funciona para limitar los bytes escritos y nula-TERMINACIÓN la cadena:

sprintf(dest, sizeof (dest), "%s", src); 

también devuelve el número de bytes que hubiera escrito, por lo que puede decir si el truncamiento se llevó a cabo.

Cuestiones relacionadas