Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x5008h: Prohibición de funciones obsoletas o inseguras (gets, atoi)

Compilacion, preprocesador y seguridad (0x50XX)

Universidad Nacional de Río Negro

0x5008h: Prohibición de funciones obsoletas o inseguras (gets, atoi)

Enunciado normativo

NO DEBEN usarse gets (eliminada en C11) ni atoi. Para leer texto se usa fgets; para convertir a entero, strtol con verificación de errores.

¿Por qué existe esta regla?

El problema

gets lee sin conocer el tamaño del destino, así que desborda el buffer con entradas largas; el comité de C la retiró por ser imposible de usar con seguridad. atoi convierte una cadena a int pero no informa si la conversión fue válida: si la cadena no es numérica devuelve 0 (indistinguible de un cero legítimo) y si el valor excede el rango de int el comportamiento es indefinido. El programa sigue como si nada.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Comportamiento indefinidogets desborda la pila; atoi con desbordamiento es UB (C11 §7.22.1.2).
Bug silenciosoatoi("abc") devuelve 0; el error nunca se detecta.
Compilación/enlacegets no existe en C11 ni en glibc reciente: error de enlace.

Fundamento en el estándar y en la cátedra

ISO/IEC 9899:2011 §7.22.1.2 describe atoi y explicita que si el valor no puede representarse el comportamiento es indefinido. gets fue eliminada del estándar, por lo que su uso es directamente no conforme. strtol (§7.22.1.4) provee endptr y errno, y fgets (§7.21.7.2) acota la lectura. La cátedra evalúa con entradas adversarias, de modo que ambas prohibiciones son obligatorias.

Alcance y excepciones

Aplica a todo el código. Excepción discutible: atoi("42") sobre un literal no puede fallar, pero la cátedra prefiere uniformidad y prohíbe la función siempre. Para punto flotante rige lo mismo con atof, reemplazada por strtod.

Ejemplos exhaustivos

❌ Contraejemplo 1 — gets para leer una línea

#include <stdio.h>

void pedir_nombre(char *buf)
{
    printf("Nombre: ");
    gets(buf);
}

Por qué falla: gets no sabe cuánto mide buf y escribe toda la línea. Además, el archivo no compila con -std=c11 porque la función ya no está declarada.

❌ Contraejemplo 2 — atoi sin control de error

#include <stdlib.h>

int convertir(const char *texto)
{
    return atoi(texto);
}

Por qué falla: atoi("hola") devuelve 0, y atoi("999999999999") desborda con comportamiento indefinido. No hay forma de saber, desde el retorno, si la conversión fue correcta.

✅ Ejemplo conforme 1 — fgets acotado con control de retorno

#include <stdio.h>
#include <string.h>

int pedir_nombre(char *buf, size_t tam)
{
    if (fgets(buf, tam, stdin) == NULL) {
        return -1;
    }
    buf[strcspn(buf, "\n")] = '\0';
    return 0;
}

fgets nunca escribe más de tam - 1 bytes y avisa con NULL si hubo error o fin de archivo. El retorno entero comunica el fallo al llamador.

✅ Ejemplo conforme 2 — strtol con validación completa

#include <errno.h>
#include <stdlib.h>

int convertir(const char *texto, long *resultado)
{
    char *fin = NULL;
    errno = 0;

    long valor = strtol(texto, &fin, 10);
    if (fin == texto || *fin != '\0' || errno == ERANGE) {
        return -1;
    }
    *resultado = valor;
    return 0;
}

strtol informa por partida doble: fin señala dónde terminó la conversión (si no avanzó o sobró texto, falló) y errno == ERANGE detecta el desbordamiento de long. Convive con 0x500Bh: Inclusión obligatoria de cabeceras estándar para funciones de la biblioteca C (incluir cabeceras) y con 0x5002h: Desarrollá y compilá siempre con todas las advertencias del compilador activadas.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cReporta 0x5008h ante gets y atoi.
gcc / clanggcc -std=c11 -Wall -Wextra -Werror -pedantic archivo.cimplicit declaration of function 'gets' y fallo de enlace.

Checklist de autocontrol

Reglas relacionadas

Antipatrón: Invocación de la función prohibida gets()

Síntoma en el código del estudiante

Lecturas de cadenas con gets a un búfer de tamaño fijo:

char buf[100];
gets(buf);

También aparece la conversión ciega con atoi, que la misma regla prohíbe:

int cantidad = atoi(entrada);

Ambas funciones carecen de toda verificación de límites o de errores.

Diagnóstico

Mecanismo del defecto

gets lee caracteres desde stdin hasta encontrar un salto de línea o el fin de archivo, y no recibe el tamaño del búfer destino. Escribe cuantos caracteres lleguen, agregando después el '\0': cualquier línea más larga que el arreglo desborda la pila. Por ese motivo fue declarada obsoleta en C99 y eliminada de la biblioteca estándar en C11. No existe una versión segura de gets; su hueco lo ocupa fgets.

atoi falla en silencio: devuelve 0 tanto si la cadena es "0" como si es "hola" o si el valor excede el rango de int (desbordamiento indefinido). No hay forma de distinguir una entrada válida de una basura.

Consecuencia observable

Fundamento en el estándar C11

gets ya no forma parte de ISO C11: se retiró de <stdio.h> por irrecuperablemente insegura. La función de reemplazo es fgets (C11 §7.21.7.2), que recibe n y lee a lo sumo n - 1 caracteres más el terminador, por lo que nunca desborda. Para conversiones robustas se usa strtol (C11 §7.22.1.4), que informa mediante endptr dónde se detuvo el análisis y permite detectar errores de rango con errno.

Corrección idiomática

❌ Código con el antipatrón
#include <stdio.h>
#include <stdlib.h>

void leer_nombre(void)
{
    char buf[100];
    gets(buf);
    int cantidad = atoi(buf);
    printf("%s %d\n", buf, cantidad);
}
✅ Código refactorizado
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void leer_nombre(void)
{
    char buf[100];

    if (fgets(buf, sizeof(buf), stdin) == NULL) {
        return;
    }

    buf[strcspn(buf, "\n")] = '\0';

    char *fin = NULL;
    errno = 0;
    long cantidad = strtol(buf, &fin, 10);

    if (fin == buf || *fin != '\0' || errno == ERANGE) {
        printf("Entrada invalida\n");
        return;
    }

    printf("%s %ld\n", buf, cantidad);
}

fgets conserva el salto de línea; se recorta con strcspn para no arrastrarlo a la comparación ni a la conversión.

Errores típicos al compilar o ejecutar

aviso.c:6:5: error: implicit declaration of function 'gets'; did you mean 'fgets'? [-Wimplicit-function-declaration]
    6 |     gets(buf);
      |     ^~~~
      |     fgets

En ejecución, cuando el binario aún enlaza una versión vieja:

*** stack smashing detected ***: terminated
Aborted (core dumped)

Checklist de verificación

Reglas relacionadas