Regla 0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada
Funciones, contratos y modularizacion (0x20XX)
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 consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | Dos argumentos del mismo tipo se intercambian en la llamada. |
| Legibilidad | La llamada ocupa varias líneas y se vuelve ilegible. |
| Acoplamiento | El llamador debe conocer el orden exacto de todos los datos. |
| Mantenibilidad | Agregar 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¶
Pasar por valor o por puntero: un
structgrande se pasa por punteroconst(0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique); uno chico puede pasarse por valor.Parámetros de salida: si además hay varios resultados, considerá devolver un
structo recibir un único puntero de salida.Constructores:
crear_usuariorecibe el struct completo, lo que puede ocultar validaciones; documentá la precondición (0x2003h: Todas las funciones deben incluir documentación completa y estructurada).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Firma con cinco o más parámetros. |
gcc / clang | gcc -Wall -Wextra -Wmissing-prototypes -std=c11 ... | Declaración larga sin prototipo que la respalde. |
| Revisión manual | — | Llamada con argumentos que hay que contar con el dedo. |
Checklist de autocontrol¶
¿Mi función tiene cuatro parámetros o menos?
¿Los parámetros que viajan juntos pertenecen a un
struct?¿El nombre del
structdescribe la entidad, no sus campos?¿La llamada se puede leer sin contar posiciones?
Reglas relacionadas¶
0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) — demasiados parámetros suele indicar varias responsabilidades.
0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t — el tipo que empaqueta los parámetros se define con
typedefy sufijo_t.0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique — el
structde solo lectura se pasa comoconst.0x2003h: Todas las funciones deben incluir documentación completa y estructurada — el contrato documenta la precondición de cada parámetro.
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 intercambiadosChecklist de verificación¶
¿La función supera los cuatro parámetros?
¿Los parámetros del mismo tipo podrían intercambiarse sin error?
¿Los datos que viajan juntos forman una entidad que puedo nombrar?
¿Puedo leer la llamada sin contar posiciones?
Reglas relacionadas¶
0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada — regla que norma este defecto: máximo cuatro parámetros.
0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) — parámetros de más suelen indicar responsabilidades de más.
0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t — el
structque agrupa los datos se define con sufijo_t.0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique — el
structde solo lectura se pasa comoconst.