vida tipos sustitucion simple reacciones reaccion quimicas ejemplos doble desplazamiento descomposicion cotidiana c language-lawyer glibc libc

tipos - Dado que el comité de la Norma C no estandarizó un reemplazo simple para get(), ¿qué debería ser?



sustitucion simple ejemplos (3)

La función gets se desaprobó por primera vez en C99 y finalmente se eliminó en C11. Sin embargo, no hay un reemplazo directo para ello en la biblioteca de C.

fgets() no es un reemplazo directo porque no elimina el ''/n'' final, que puede estar ausente al final del archivo. Muchos programadores también se equivocan.

Hay una sola línea para eliminar el buf[strcspn(buf, "/n")] = ''/0''; línea: buf[strcspn(buf, "/n")] = ''/0''; , pero no es trivial y con frecuencia requiere una explicación. También puede ser ineficiente.

Esto es contraproducente. Muchos principiantes todavía usan gets() porque sus profesores son débiles o sus tutoriales obsoletos.

Microsoft propuso gets_s() y muchas funciones relacionadas, pero no trunca de manera silenciosa las líneas demasiado largas, el comportamiento en esta violación de restricción no es exactamente simple.

Tanto BSD como GNU libc tienen getline , estandarizado en POSIX, que asigna o reasigna un búfer a través de realloc ...

¿Cuál es la mejor manera de enseñar a los principiantes sobre este lío?


En mi opinión, cualquier reemplazo tendría que pasar el size , así como el destino char * , lo que requeriría cambios en el código que dependían significativamente de cada caso. Una talla única no se consideró posible, ya que el size menudo se pierde / no se pasa por el momento en que el código llega a gets() . Teniendo en cuenta que teníamos una advertencia de 12 años (C99 a C11), sospechamos que el comité sintió que el problema desaparecería en 2011.

¡Decir ah!

El comité de la norma C debería haber hecho un reemplazo que también pasara en el tamaño del destino. Me gusta lo siguiente. (esto probablemente tiene un problema de colisión de nombre)

char *gets_replacement(char *s, size_t size);

fgets() un reemplazo basado en fgets() que aprovecha el VLA (opcional en C11)

char *my_gets(char *dest, size_t size) { // +2 one for /n and 1 to detect overrun char buf[size + 2]; if (fgets(buf, sizeof buf, stdin) == NULL) { // improve error handling - see below comment if (size > 0) { *buf = ''/0''; } return NULL; } size_t len = strlen(buf); if (len > 0 && buf[len - 1] == ''/n'') { buf[--len] = ''/0''; } // If input would have overrun the original gets() if (len >= size) { // or call error handler if (size > 0) { *buf = ''/0''; } return NULL; } return memcpy(dest, buf, len + 1); }


Esta pregunta requiere en gran medida una especulación que no sea una cita de las actas del comité o algo así, pero como principio general, el comité (WG14) generalmente evita inventar nuevas interfaces y prefiere documentar y hacer prácticas existentes rigurosas (cosas como snprintf , long long , el inttypes.h , etc.) y, a veces, adopta otras normas / definiciones de interfaz fuera de C (p. ej., matemáticas complejas de punto flotante IEEE, modelo atómico de C ++, etc.). gets no tiene tal reemplazo que adoptar, probablemente porque fgets generalmente se considera superior (no tiene pérdidas cuando el archivo finaliza sin una nueva línea). Si realmente quieres un reemplazo directo, algo como esto funciona:

char buf[100]; scanf("%99[^/n]%*1[/n]", buf);

Por supuesto, es klunky de usar, especialmente cuando el tamaño del búfer es variable.


La naturaleza de la pregunta es tal que habrá especulaciones y opiniones. Pero podríamos encontrar alguna información de la lógica C99 y el estándar C11.

El razonamiento de C99 , cuando gets() fue desaprobado, establece la siguiente razón para desaprobarlo:

Debido a que get no comprueba el exceso de búfer, generalmente no es seguro utilizarlo cuando su entrada no está bajo el control del programador. Esto ha hecho que algunos cuestionen si debería aparecer en la Norma. El Comité decidió que la obtención de información era útil y conveniente en aquellas circunstancias especiales en las que el programador tiene un control adecuado sobre la entrada, y como una práctica existente de larga data, necesitaba una especificación estándar. En general, sin embargo, la función preferida es fgets (ver §7.19.7.2).

Tampoco creo que los gets_s() puedan considerarse como una alternativa. Porque gets_s() es una interfaz opcional. C11 en realidad recomienda fgets() sobre gets_s() :

§K.3.5.4.1 , borrador C11

La función fgets permite que los programas escritos correctamente procesen con seguridad las líneas de entrada durante demasiado tiempo para almacenarlas en la matriz de resultados. En general, esto requiere que las personas que llaman a fgets presten atención a la presencia o ausencia de un carácter de nueva línea en la matriz de resultados. Considere usar fgets (junto con cualquier procesamiento necesario basado en caracteres de nueva línea) en lugar de gets_s.

Así que eso nos deja con fgets() como el único reemplazo real para gets() en ISO C. fgets() es equivalente a gets() excepto que se leería en la nueva línea si hubiera espacio en el búfer. Entonces, ¿vale la pena introducir una nueva interfaz que tenga una pequeña mejora con respecto a una antigua y ampliamente utilizada ( fgets() )? OMI, no.

Además, muchas aplicaciones del mundo real no se limitan a ISO C solo. Así que hay una oportunidad de usar extensiones y POSIX getline() etc. como reemplazo.

Si es necesario encontrar una solución de escritura dentro de ISO C, entonces es bastante fácil escribir una envoltura alrededor de fgets() todos modos, como my_fgets() que eliminaría la nueva línea, si está presente.

Por supuesto, enseñar fgets() a los recién llegados implica explicar sobre el posible problema de nueva línea. Pero en mi opinión, no es tan difícil de entender y alguien con la intención de aprender C debería poder entenderlo rápidamente. Esto (encontrar el último personaje y reemplazarlo si es el carácter "X") podría incluso considerarse como un buen ejercicio para un principiante.

Por lo tanto, a la luz de las razones mencionadas anteriormente, diría que no hay una necesidad abrumadora de una nueva función en ISO C como un verdadero reemplazo para gets() .