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 0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada

Funciones, contratos y modularizacion (0x20XX)

Universidad Nacional de Río Negro

0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada

Enunciado normativo

NO DEBE declararse una función con más de cuatro parámetros de entrada. Cuando un conjunto de datos viaja siempre junto, DEBE empaquetarse en un struct (o en un TDA) y pasarse mediante un único puntero.

¿Por qué existe esta regla?

El problema

Cada parámetro es una pieza de información que el llamador debe recordar y ordenar. Con muchos parámetros, el error de invocación es estadísticamente probable: dos int consecutivos intercambiados compilan sin chistar y producen un resultado incorrecto. La firma larga también es un síntoma: reunir cinco datos sueltos suele indicar que existe una entidad conceptual (un “usuario”, una “configuración”, un “pedido”) que no fue modelada.

Un struct da nombre al conjunto, reduce la firma a un puntero y permite que la función opere sobre una entidad coherente. Además, si el conjunto crece mañana, la firma no cambia.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Bug silenciosoDos argumentos del mismo tipo se intercambian en la llamada.
LegibilidadLa llamada ocupa varias líneas y se vuelve ilegible.
AcoplamientoEl llamador debe conocer el orden exacto de todos los datos.
MantenibilidadAgregar un dato obliga a cambiar todas las llamadas.

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

C11 no limita la cantidad de parámetros; de hecho, los arreglos son “ajustados” a punteros y los parámetros tienen duración automática dentro de la función (§6.9.1). La cátedra fija el umbral de cuatro por ergonomía y por diseño: es un disparador para preguntarse si falta modelar un tipo. Se relaciona con 0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) (responsabilidad única) y con 0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t (typedef de estructuras) para el reemplazo idiomático.

Alcance y excepciones

Cuenta los parámetros de entrada. El puntero this/contexto no aplica en C. No se cuentan los parámetros de salida por puntero como si fueran de entrada, aunque también conviene acotarlos.

Excepción razonable: funciones de la biblioteca estándar con firmas impuestas (printf, qsort) no pueden cambiarse. Tampoco se exige refactorizar una función de tres parámetros “por las dudas”: el umbral es cuatro, y solo se actúa cuando se supera.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Datos que viajan juntos y sueltos

void crear_usuario(const char *nombre, const char *apellido, int edad,
                   int dni, const char *mail, const char *telefono);

Por qué falla: seis parámetros describen una sola entidad. Nada impide pasar edad donde va dni; ambos son int, así que el compilador acepta la llamada incorrecta. La firma tampoco expresa que esos datos forman un usuario.

❌ Contraejemplo 2 — Función de dibujo con demasiados controles

void dibujar(int x, int y, int ancho, int alto, int color, int grosor,
             bool relleno, bool sombra);

Por qué falla: ocho parámetros sin estructura. La llamada dibujar(10, 20, 30, 40, 0, 1, true, false) es imposible de revisar, y el orden es la única defensa contra un intercambio de valores.

✅ Ejemplo conforme 1 — Struct que nombra el conjunto

struct usuario_t {
    const char *nombre;
    const char *apellido;
    int edad;
    int dni;
};

void crear_usuario(const struct usuario_t *u);

La firma dice “recibe un usuario”; el orden de los campos deja de ser un contrato frágil y el tipo documenta qué datos se esperan.

✅ Ejemplo conforme 2 — Configuración de dibujo empaquetada

struct estilo_t {
    int color;
    int grosor;
    bool relleno;
    bool sombra;
};

void dibujar(int x, int y, const struct rectangulo_t *r,
             const struct estilo_t *estilo);

Cada struct agrupa datos de una misma naturaleza. La función recibe cuatro parámetros, cada uno con un rol claro, y cumple el límite.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cFirma con cinco o más parámetros.
gcc / clanggcc -Wall -Wextra -Wmissing-prototypes -std=c11 ...Declaración larga sin prototipo que la respalde.
Revisión manualLlamada con argumentos que hay que contar con el dedo.

Checklist de autocontrol

Reglas relacionadas

Antipatrón: Función con excesiva cantidad de parámetros (> 5)

Síntoma en el código del estudiante

Firmas que ocupan más de una línea y llamadas donde hay que contar posiciones con el dedo. Los parámetros suelen ser del mismo tipo (int, const char *), lo que deja la puerta abierta a intercambios silenciosos.

Diagnóstico

Mecanismo del defecto

Cada parámetro es un valor que el llamador debe copiar a un registro o a la pila en un orden posicional fijo. Cuando varios comparten el mismo tipo, el compilador no puede distinguir un intercambio: crear(30, 40123456) y crear(40123456, 30) son la misma llamada válida, pero una está mal. La firma larga también dispersa la responsabilidad: es probable que la función esté haciendo varias cosas (0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única)).

Además, agregar un parámetro obliga a editar todas las llamadas, y un struct que agrupe los datos relacionados cambiaría la firma sin afectar a los llamadores. La pila recibe más argumentos de los necesarios y el acoplamiento crece.

Consecuencia observable

Resultados incorrectos por argumentos intercambiados que el compilador no detecta, y llamadas ilegibles que el docente no puede revisar de un vistazo. La regla 0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada es el disparador: superar cuatro parámetros obliga a modelar el conjunto.

Fundamento en el estándar C11

La lista de parámetros de una función se declara en su prototipo y cada parámetro tiene duración automática (§6.9.1). El estándar no impone un límite de cantidad, pero el orden posicional es la única forma de asociarlos, lo que hace frágil cualquier lista larga. Los arreglos se ajustan a punteros (§6.7.6.3), de modo que “más parámetros” nunca es una solución de memoria, solo de legibilidad.

Corrección idiomática

❌ Código con el antipatrón
void crear_usuario(const char *nombre, const char *apellido, int edad,
                   int dni, const char *mail, const char *telefono);
✅ Código refactorizado
struct usuario_t {
    const char *nombre;
    const char *apellido;
    int edad;
    int dni;
    const char *mail;
    const char *telefono;
};

void crear_usuario(const struct usuario_t *u);

Errores típicos al compilar o ejecutar

# No hay error de compilación: el bug es silencioso.
$ ./programa
usuario creado con dni=31 y edad=40123456   # argumentos intercambiados

Checklist de verificación

Reglas relacionadas