¿Por qué debería usar strncpy en lugar de strcpy?

12 minutos de lectura

avatar de usuario
Kredns

Editar: he agregado la fuente para el ejemplo.

Me encontré con este ejemplo:

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

Que produjo esta salida:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

Lo que me hace preguntarme por qué alguien querría este efecto. Parece que sería confuso. Este programa me hace pensar que básicamente podría copiar el nombre de alguien (por ejemplo, Tom Brokaw) con Tom Bro763.

¿Cuáles son las ventajas de usar strncpy() terminado strcpy()?

  • Creo que querías preguntar “¿Por qué diablos alguien usaría strcpy en vez de strncpy?”

    – Sam Harwell

    11 de agosto de 2009 a las 5:24

  • Mi diatriba sobre el tema de strncpy()

    –Keith Thompson

    14 de diciembre de 2014 a las 5:28

  • @KeithThompson: Desde el punto de vista del diseño, creo strncat es mas tonto que strncpy; ¿Con qué frecuencia se sabrá cuánto espacio queda en un búfer después de una cadena de longitud desconocida? Si se conoce la longitud de la cadena de destino, se debe encontrar la longitud de la fuente (si se desconoce), sujetar ese valor al espacio de búfer disponible y luego usar memcpy para copiar la parte que encajará y almacenar manualmente un cero después. Si no se conoce la longitud de la cadena de destino, normalmente habrá que encontrar su longitud para saber cuánto espacio hay disponible más allá, en cuyo caso se aplica lo anterior.

    – Super gato

    01/09/2015 a las 20:49

avatar de usuario
coste y flete

Él strncpy() La función fue diseñada con un problema muy particular en mente: manipular cadenas almacenadas a la manera de las entradas de directorio originales de UNIX. Estos usaban una matriz corta de tamaño fijo (14 bytes) y solo se usaba un terminador nulo si el nombre del archivo era más corto que la matriz.

Eso es lo que hay detrás de las dos rarezas de strncpy():

  • No pone un terminador nulo en el destino si está completamente lleno; y
  • Siempre llena completamente el destino, con nuls si es necesario.

Por un “más seguro strcpy()“, es mejor que uses strncat() al igual que:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

Eso siempre anulará el resultado y no copiará más de lo necesario.

  • Pero, por supuesto, strncpy tampoco es siempre lo que quieres: strncpy acepta el número máximo de caracteres para agregar y no el tamaño del búfer de destino … Pero eso es solo una cosa menor, por lo que probablemente no sea un problema a menos que intente concatenar una cadena en otra.

    – David Wolever

    11 de agosto de 2009 a las 23:59

  • No sabía el motivo, y es muy relevante para lo que estoy trabajando en atm.

    – Matt Carpintero

    21 de septiembre de 2010 a las 16:18

  • La función strncpy() está diseñada para almacenar cadenas en formato de relleno nulo de longitud fija. Dicho formato se usó para las entradas de directorio originales de Unix, pero también se usa en muchos otros lugares, ya que permite almacenar una cadena de 0-N bytes en N bytes de almacenamiento. Incluso hoy en día, muchas bases de datos utilizan cadenas con relleno nulo en sus campos de cadena de longitud fija. La confusión con strncpy() surge del hecho de que convierte cadenas al formato FLNP. Si lo que uno necesita es una cuerda FLNP, eso es maravilloso. Si se necesita una cadena terminada en nulo, uno mismo debe proporcionar la terminación.

    – Super gato

    20 de noviembre de 2011 a las 23:26

  • ¿Por qué tenemos que escribir? dest[0] = '\0'; antes de la llamada strncat? ¿Le importaría explicarme, señor?

    – snr

    6 de marzo de 2019 a las 19:31

  • @snr: strncat() concatena la cadena de origen al final de la cadena de destino. Solo queremos copiar la cadena de origen al destino, por lo que primero establecemos el destino en la cadena vacía, eso es lo que dest[0] = '\0'; hace.

    – café

    6 de marzo de 2019 a las 22:36

avatar de usuario
Sinan Ünür

Si bien sé la intención detrás strncpy, no es realmente una buena función. Evite ambos. Raymond Chen explica.

Personalmente, mi conclusión es simplemente evitar strncpy y todos sus amigos si se trata de cadenas terminadas en cero. A pesar de “str” ​​en el nombre, estas funciones no producen cadenas terminadas en nulo. Convierten una cadena terminada en nulo en un búfer de caracteres sin formato. Usarlos donde se espera una cadena terminada en nulo como el segundo búfer es simplemente incorrecto. No solo no puede obtener la terminación nula adecuada si la fuente es demasiado larga, sino que si la fuente es corta, obtiene un relleno nulo innecesario.

Consulte también ¿Por qué strncpy es inseguro?

strncpy combate el desbordamiento del búfer requiriendo que le pongas una longitud. strcpy depende de un seguimiento \0que no siempre puede ocurrir.

En segundo lugar, no entiendo por qué eligió copiar solo 5 caracteres en una cadena de 7 caracteres, pero está produciendo el comportamiento esperado. Solo está copiando sobre el primero. n personajes, donde n es el tercer argumento.

Él n todas las funciones se utilizan como codificación defensiva contra desbordamientos de búfer. Utilícelos en lugar de funciones anteriores, como strcpy.

  • Ver lysator.liu.se/c/rat/d11.html : strncpy se introdujo inicialmente en la biblioteca C para tratar con campos de nombre de longitud fija en estructuras como entradas de directorio. Dichos campos no se usan de la misma manera que las cadenas: el nulo final no es necesario para un campo de longitud máxima, y ​​establecer bytes finales para nombres más cortos en nulo asegura comparaciones eficientes en cuanto a campo. strncpy no es por origen una “línea delimitada”, y el Comité ha preferido reconocer la práctica existente en lugar de alterar la función para adaptarla mejor a dicho uso.

    – Sinan Ünür

    11 de agosto de 2009 a las 6:20

  • No estoy seguro de por qué esto está obteniendo muchos votos positivos: strncpy nunca fue pensado como una alternativa más segura que strcpy y, de hecho, no es más seguro ya que no termina en cero la cadena. También tiene una funcionalidad diferente en el sentido de que rellena la longitud suministrada con caracteres NUL. Como dice caf en su respuesta, es para sobrescribir cadenas en una matriz de tamaño fijo.

    – Varilla

    11 de agosto de 2009 a las 6:25

  • Queda el hecho de que strncpy es no una versión más segura de strcpy.

    – Sinan Ünür

    11 de agosto de 2009 a las 6:33

  • @Sinan: Nunca dije que fuera más seguro. Es defensivo. Te obliga a poner un largo, ergo te hace pensar en lo que estás haciendo. Hay mejores soluciones, pero el hecho es que la gente usaría (y lo hace) strncpy en vez de strcpy porque es una función mucho más defensiva… que es lo que dije.

    –Eric

    11 de agosto de 2009 a las 6:36

  • Las funciones n se utilizan como codificación defensiva contra desbordamientos de búfer. Úselos en lugar de funciones más antiguas, como strcpy. esto es cierto para snprintfpero irrelevante para strncat y completamente falso para strncpy. ¿Cómo podría esta respuesta obtener tantos votos a favor? Muestra cuán mala es la situación con respecto a esta función falsa. Usarlo no es defensivo: en la mayoría de las situaciones, el programador no comprende su semántica y crea una cadena potencialmente no terminada en cero.

    – chqrlie

    5 de febrero de 2016 a las 19:16

avatar de usuario
patricio schlüter

Lo que buscas es la función. strlcpy() que termina siempre la cadena con 0 e inicializa el búfer. También es capaz de detectar desbordamientos. El único problema es que no es (realmente) portátil y solo está presente en algunos sistemas (BSD, Solaris). El problema con esta función es que abre otra lata de gusanos como se puede ver en las discusiones sobre
http://en.wikipedia.org/wiki/Strlcpy

Mi opinión personal es que es mucho más útil que strncpy() y strcpy(). Tiene un mejor rendimiento y es un buen compañero para snprintf(). Para plataformas que no lo tienen, es relativamente fácil de implementar. (para la fase de desarrollo de una aplicación sustituyo estas dos funciones (snprintf() y strlcpy()) con una versión de captura que aborta brutalmente el programa en desbordamientos de búfer o truncamientos. Esto permite atrapar rápidamente a los peores infractores. Especialmente si trabajas en un código base de otra persona.

EDITAR: strlcpy() se puede implementar fácilmente:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}

strncpy NO es más seguro que strcpy, solo intercambia un tipo de error con otro. En C, cuando maneja cadenas C, necesita saber el tamaño de sus búferes, no hay forma de evitarlo. strncpy estaba justificado por el directorio mencionado por otros, pero de lo contrario, nunca debe usarlo:

  • si conoce la longitud de su cadena y búfer, ¿por qué usar strncpy? Es un desperdicio de poder de cómputo en el mejor de los casos (agregar 0 inútil)
  • si no conoce las longitudes, corre el riesgo de truncar silenciosamente sus cadenas, lo cual no es mucho mejor que un desbordamiento de búfer

  • Creo que esta es una buena descripción para strncpy, así que la voté. strncpy tiene su propio conjunto de problemas. Supongo que esa es la razón por la que, por ejemplo, glib tiene sus propias extensiones. Y sí, es desafortunado que usted, como programador, tenga que ser consciente del tamaño de todas las matrices. La decisión de tener una matriz de caracteres terminada en 0 como cadena, nos ha costado muy caro a todos….

    – Federico

    21 de octubre de 2009 a las 16:04

  • Las cadenas con relleno cero son bastante comunes cuando se almacenan datos en archivos de formato fijo. Sin duda, la popularidad de cosas como los motores de bases de datos y XML, junto con las expectativas cambiantes de los usuarios, han provocado que los archivos de formato fijo sean menos comunes que hace 20 años. No obstante, tales archivos son a menudo los medios más eficientes en el tiempo para almacenar datos. Excepto cuando hay una gran disparidad entre la longitud esperada y la máxima de los datos en un registro, es mucho más rápido leer un registro como un solo fragmento que contiene algunos datos no utilizados que leer un registro dividido en varios fragmentos.

    – Super gato

    20 de noviembre de 2011 a las 23:39

  • Simplemente se hizo cargo del mantenimiento del código heredado, que usaba g_strlcpy(), por lo que no sufre las ineficiencias de relleno, pero, por supuesto, el recuento de bytes transferidos NO se mantuvo, por lo que el código truncó silenciosamente el resultado.

    – usuario2548100

    28/01/2014 a las 19:37

Él strncpy() La función es la más segura: debe pasar la longitud máxima que puede aceptar el búfer de destino. De lo contrario, podría suceder que la cadena de origen no termine correctamente en 0, en cuyo caso el strcpy() La función podría escribir más caracteres en el destino, corrompiendo cualquier cosa que esté en la memoria después del búfer de destino. Este es el problema de saturación de búfer utilizado en muchos exploits.

También para funciones API POSIX como read() que no coloca el 0 final en el búfer, pero devuelve el número de bytes leídos, colocará manualmente el 0 o lo copiará usando strncpy().

En su código de ejemplo, index en realidad no es un índice, sino un count – dice cuantos caracteres a lo sumo para copiar desde el origen al destino. Si no hay un byte nulo entre los primeros n bytes del origen, la cadena colocada en el destino no terminará en un valor nulo.

  • Creo que esta es una buena descripción para strncpy, así que la voté. strncpy tiene su propio conjunto de problemas. Supongo que esa es la razón por la que, por ejemplo, glib tiene sus propias extensiones. Y sí, es desafortunado que usted, como programador, tenga que ser consciente del tamaño de todas las matrices. La decisión de tener una matriz de caracteres terminada en 0 como cadena, nos ha costado muy caro a todos….

    – Federico

    21 de octubre de 2009 a las 16:04

  • Las cadenas con relleno cero son bastante comunes cuando se almacenan datos en archivos de formato fijo. Sin duda, la popularidad de cosas como los motores de bases de datos y XML, junto con las expectativas cambiantes de los usuarios, han provocado que los archivos de formato fijo sean menos comunes que hace 20 años. No obstante, tales archivos son a menudo los medios más eficientes en el tiempo para almacenar datos. Excepto cuando hay una gran disparidad entre la longitud esperada y la máxima de los datos en un registro, es mucho más rápido leer un registro como un solo fragmento que contiene algunos datos no utilizados que leer un registro dividido en varios fragmentos.

    – Super gato

    20 de noviembre de 2011 a las 23:39

  • Simplemente se hizo cargo del mantenimiento del código heredado, que usaba g_strlcpy(), por lo que no sufre las ineficiencias de relleno, pero, por supuesto, el recuento de bytes transferidos NO se mantuvo, por lo que el código truncó silenciosamente el resultado.

    – usuario2548100

    28/01/2014 a las 19:37

avatar de usuario
bashmohandes

strncpy es una versión más segura de strcpy, de hecho, nunca debe usar strcpy debido a su posible vulnerabilidad de desbordamiento de búfer que hace que su sistema sea vulnerable a todo tipo de ataques

  • Ver lysator.liu.se/c/rat/d11.html : La función strncpy strncpy se introdujo inicialmente en la biblioteca C para manejar campos de nombre de longitud fija en estructuras como entradas de directorio. Dichos campos no se usan de la misma manera que las cadenas: el nulo final no es necesario para un campo de longitud máxima, y ​​establecer bytes finales para nombres más cortos en nulo asegura comparaciones eficientes en cuanto a campo. strncpy no es por origen un “strcpy acotado”, y el Comité ha preferido reconocer la práctica existente en lugar de alterar la función para adaptarla mejor a dicho uso.

    – Sinan Ünür

    11 de agosto de 2009 a las 6:19

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad