Regla 0x2002h: Las funciones no deben contener printf o scanf, a menos que ese sea su propósito explícito
Funciones, contratos y modularizacion (0x20XX)
0x2002h: Las funciones no deben contener printf o scanf, a menos que ese sea su propósito explícito¶
Enunciado normativo¶
NO DEBE mezclarse la lógica de cálculo con llamadas a
printfoscanf. Una función SÓLO PUEDE leer o escribir por consola si su nombre y su documentación declaran que esa es exactamente su responsabilidad.
¿Por qué existe esta regla?¶
El problema¶
Una función que calcula y además imprime tiene dos motivos para cambiar: la
fórmula y el formato de salida. Peor: su resultado vive en un efecto lateral, no
en el valor de retorno, así que para verificarla hay que capturar la pantalla o
simular el teclado. La función queda atada a stdin/stdout, dos flujos
globales difíciles de reemplazar en una prueba automática. Separar cálculo de
presentación convierte al cálculo en una caja pura que recibe datos y devuelve
un resultado.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Testing | No se prueba con assert sin redirigir la salida (0x8001h: Una aserción por cada función de prueba). |
| Reutilización | La lógica no sirve para otra interfaz ni para un programa sin consola. |
| Mantenibilidad | Cambiar un mensaje obliga a tocar la función que calcula. |
| Ruido | El cuerpo se llena de formato, comas y \n ajenos al algoritmo. |
Fundamento en el estándar y en la cátedra¶
C11 declara las funciones de E/S con formato en <stdio.h> (§7.21.6):
printf escribe en stdout y scanf lee de stdin. La norma no prohíbe
usarlas en cualquier función; la cátedra las restringe por diseño, siguiendo la
responsabilidad única (0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única)) y protegiendo la testabilidad de
0x8001h: Una aserción por cada función de prueba.
Alcance y excepciones¶
Cubre toda función cuyo propósito no sea interactuar con el usuario. Sí se
permiten printf/scanf en funciones de interfaz nombradas como tales
(mostrar_resultado, leer_edades), en main y en rutinas de registro o
diálogo. La E/S sobre archivos (fprintf/fscanf) se rige por 0x4001h: Manejá correctamente la apertura y cierre de archivos
y 0x4002h: Validá los retornos de las operaciones de lectura y escritura de archivos.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Cálculo e impresión en la misma función¶
double calcular_promedio(const int v[], size_t n)
{
int suma = 0;
for (size_t i = 0; i < n; i++) {
suma += v[i];
}
double promedio = (double)suma / (double)n;
printf("El promedio es %.2f\n", promedio);
return promedio;
}El nombre promete calcular, pero también imprime; probarla dispara salida por pantalla.
❌ Contraejemplo 2 — Lectura por teclado dentro de la lógica¶
int buscar_mayor(struct lista_t *l)
{
int valor;
printf("Ingrese un valor de corte: ");
scanf("%d", &valor);
int mayor = l->datos[0];
for (size_t i = 1; i < l->tam; i++) {
if (l->datos[i] > mayor) {
mayor = l->datos[i];
}
}
return mayor;
}Mezcla una lectura interactiva con la búsqueda; además ignora el retorno de
scanf (0x4002h: Validá los retornos de las operaciones de lectura y escritura de archivos) y deja valor sin uso (0x2006h: Mantené el alcance de las variables al mínimo posible).
✅ Ejemplo conforme 1 — Cálculo puro¶
double calcular_promedio(const int v[], size_t n)
{
if (n == 0) {
return 0.0;
}
long suma = 0;
for (size_t i = 0; i < n; i++) {
suma += v[i];
}
return (double)suma / (double)n;
}Se prueba con assert(calcular_promedio(v, 0) == 0.0) sin tocar la consola.
✅ Ejemplo conforme 2 — Interfaz separada del cálculo¶
static void mostrar_promedio(double valor)
{
printf("El promedio es %.2f\n", valor);
}
int main(void)
{
int edades[] = {20, 30, 40};
mostrar_promedio(calcular_promedio(edades, 3));
return 0;
}calcular_promedio no sabe que existe una pantalla; mostrar_promedio declara
su tarea. Cada una cambia por un motivo distinto.
⚠️ Casos límite¶
Depuración temporal: un
printfde seguimiento se elimina antes de entregar (0x0202h: No dejes código comentado (dead code) en los archivos fuente).Arreglo vacío (
n == 0): lo resuelve la función de cálculo, no la de impresión.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | printf/scanf en funciones que no son de interfaz. |
grep | grep -n "printf|scanf" modulo.c | E/S presente en módulos de lógica. |
Checklist de autocontrol¶
¿Mi función devuelve el resultado en lugar de imprimirlo?
¿El nombre declara que hace interfaz, si usa
printf?¿Separé la lectura de datos del algoritmo que los procesa?
Reglas relacionadas¶
0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) — una función, una responsabilidad; imprimir no es calcular.
0x8001h: Una aserción por cada función de prueba — sin E/S embebida, la prueba se reduce a un
assert.0x2008h: Los ejercicios deben ser resueltos mediante funciones — la solución se organiza en funciones, no en un
mainmonolítico.0x4002h: Validá los retornos de las operaciones de lectura y escritura de archivos — si hay E/S, hay que verificar su valor de retorno.