Regla 0x200Ch: Cada función debe tener a lo sumo un return
Funciones, contratos y modularizacion (0x20XX)
0x200Ch: Cada función debe tener a lo sumo un return¶
Enunciado normativo¶
DEBE concentrarse el resultado de la función en una única variable y ejecutar un solo
returnal final. La única excepción son las cláusulas de guarda de validación inicial, autorizadas por 0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda.
¿Por qué existe esta regla?¶
El problema¶
Con varios return dispersos, cada uno es una salida que hay que auditar: si
alguno olvida liberar un recurso o normalizar el resultado, aparece un camino
distinto sin que se note. Con un único return final, el resultado se construye
paso a paso y se entrega una sola vez; ese punto es el lugar natural para la
limpieza y la verificación final.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Fugas de recursos | Una salida anticipada omite el free o el fclose. |
| Bug silencioso | Un return temprano devuelve un valor no normalizado. |
| Legibilidad | Hay que rastrear todas las salidas para saber qué devuelve. |
| Testing | Los caminos de salida múltiples multiplican los casos a cubrir. |
Fundamento en el estándar y en la cátedra¶
C11 admite return en cualquier punto del cuerpo (§6.8.6.4); no hay nada
técnico que impida varios. La regla es una convención de la cátedra para que el
flujo sea predecible y la limpieza única. Convive con 0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda: las
guardas de validación inicial se aceptan porque no hay recursos adquiridos. La
prioridad es guardas al principio, un solo return después.
Alcance y excepciones¶
Aplica a funciones con lógica y recursos. No se aplica cuando la estructura
natural es un switch que retorna por case, aunque se prefiere asignar a la
variable de resultado. Excepciones: guardas (0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda), switch de
despacho y recursivas puras con ramas de expresión simple.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Retorno múltiple con limpieza olvidada¶
int cargar(const char *ruta, struct tabla_t *t)
{
FILE *f = fopen(ruta, "r");
if (f == NULL) {
return ERROR_APERTURA;
}
if (leer(f, t) != 0) {
return ERROR_LECTURA;
}
fclose(f);
return OK;
}La lectura fallida retorna sin cerrar el archivo: la limpieza quedó atada al camino feliz.
❌ Contraejemplo 2 — Cada rama retorna una vez¶
int clasificar(int valor)
{
if (valor < 0) {
return -1;
}
if (valor == 0) {
return 0;
}
return 1;
}Correcto, pero el resultado queda repartido; agregar una normalización final obligaría a repetirla en cada rama.
✅ Ejemplo conforme 1 — Resultado único y limpieza centralizada¶
int cargar(const char *ruta, struct tabla_t *t)
{
int resultado = OK;
FILE *f = fopen(ruta, "r");
if (f == NULL) {
return ERROR_APERTURA;
}
if (leer(f, t) != 0) {
resultado = ERROR_LECTURA;
}
if (fclose(f) != 0) {
resultado = ERROR_CIERRE;
}
return resultado;
}La guarda de apertura es la única salida anticipada; todos los caminos liberan.
✅ Ejemplo conforme 2 — Variable de resultado para clasificar¶
int clasificar(int valor)
{
int resultado;
if (valor < 0) {
resultado = -1;
} else if (valor == 0) {
resultado = 0;
} else {
resultado = 1;
}
return resultado;
}El valor se decide en la cadena de condiciones y se entrega en un único punto.
⚠️ Casos límite¶
Guardas iniciales:
if (p == NULL) { return ERROR; }no cuenta como retorno múltiple problemático (0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda).switchde retorno: evaluá convertirlo a asignaciones sobre el resultado.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Más de un return sin limpieza asociada. |
| Revisión manual | — | Contar salidas y verificar la limpieza en cada una. |
Checklist de autocontrol¶
¿Concentré el resultado en una variable y lo devolví al final?
¿Mis únicas salidas anticipadas son guardas de validación?
¿Todos los caminos liberan los recursos adquiridos?
Reglas relacionadas¶
0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda — guardas de entrada; su excepción sancionada.
0x2013h: Detector de bloques else superfluos tras sentencias terminales —
elseinnecesario tras un retorno anticipado.0x2003h: Todas las funciones deben incluir documentación completa y estructurada — el contrato documenta el único valor devuelto.