0x1006h: No utilizar la instrucción goto¶
Enunciado normativo¶
NO DEBE usarse la instrucción
gotoen el código de la cátedra. Toda repetición o salto condicional DEBE expresarse con las estructuras de control estándar (if,for,while,do-while,switch).
¿Por qué existe esta regla?¶
El problema¶
goto permite saltar a cualquier etiqueta del mismo cuerpo, hacia adelante o
hacia atrás, sin pasar por las condiciones que las otras estructuras imponen.
El flujo deja de ser un árbol y se vuelve un grafo: para saber qué se ejecuta
después de una línea hay que buscar todas las etiquetas y todos los saltos.
Ese costo lo paga cada lector, cada vez. El teorema de la programación
estructurada de Böhm–Jacopini demuestra que todo programa con goto puede
reescribirse con secuencia, selección e iteración; por lo tanto el goto no
aporta poder expresivo, solo oscurecimiento.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Código espagueti | Saltos cruzados que hacen imposible seguir el flujo linealmente. |
| Depuración | El contador de programa salta sin relación aparente con la línea previa. |
| Mantenibilidad | Mover una sentencia puede romper una etiqueta distante. |
| Inicialización | Un salto hacia atrás puede reintroducir un estado ya procesado. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.8.6.1 define goto; el estándar lo permite, y de hecho
admite el patrón de liberación centralizada. La cátedra adopta la prohibición
general para forzar el razonamiento estructurado en el curso introductorio. La
regla más específica 0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos admite una única excepción acotada; ante
cualquier duda, consultar con la cátedra.
Alcance y excepciones¶
Regla general:
gotoprohibido.Única excepción admitida: el salto hacia adelante a un bloque terminal de liberación de recursos, descripto en 0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos.
breakycontinueno songoto; se norman en 0x1002h: Restringí el uso de break y continue; preferí lazos con bandera de control.El
switchno requieregoto; usabreak(ver 0x1008h: Toda instrucción switch debe incluir un caso default).
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — goto simulando un lazo¶
int i = 0;
repetir:
if (i >= n)
{
goto fin;
}
procesar(valores[i]);
i++;
goto repetir;
fin:
return 0;Por qué falla: un lazo for expresa lo mismo en tres líneas. Acá el flujo
depende de dos etiquetas y tres saltos; agregar un continue equivalente
requiere otra etiqueta.
❌ Contraejemplo 2 — goto cruzando la inicialización¶
goto saltar;
int total = 0;
saltar:
printf("%d\n", total);Por qué falla: el salto omite la inicialización y total se lee con un valor
indeterminado. Es comportamiento indefinido (ISO/IEC 9899:2011 §6.2.4).
✅ Ejemplo conforme 1 — lazo estructurado equivalente¶
for (int i = 0; i < n; i++)
{
procesar(valores[i]);
}El encabezado reúne inicialización, cota e incremento; no hay etiquetas ni saltos que rastrear.
✅ Ejemplo conforme 2 — salida temprana estructurada¶
bool procesar_todo(const int valores[], size_t n)
{
for (size_t i = 0; i < n; i++)
{
if (!procesar(valores[i]))
{
return false;
}
}
return true;
}El retorno anticipado reemplaza al goto de error; es una salida legítima
dentro de una función corta (ver 0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda).
⚠️ Casos límite¶
Limpieza centralizada: el único patrón tolerado es el de 0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos; si hay múltiples recursos, evaluar una función de limpieza.
Punteros y liberación: en vez de
goto, se puede encapsular la limpieza en una función y llamarla antes de retornar.gotogenerado por macros: prohibido igual; la macro debe reescribirse.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1006h: uso de goto. |
| Búsqueda | grep -n "goto" archivo.c | Toda aparición es una violación. |
gcc | gcc -Wall -Wextra | No la señala: goto es C válido. |
Checklist de autocontrol¶
¿Queda algún
gotoy su etiqueta en el archivo?¿El lazo que el
gotosimulaba puede escribirse conforowhile?Si hay limpieza de recursos, ¿usé el patrón de 0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos?
¿Las salidas tempranas usan
returnen lugar de saltos?
Reglas relacionadas¶
0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos — excepción acotada:
gotohacia adelante a limpieza.0x1002h: Restringí el uso de break y continue; preferí lazos con bandera de control — alternativa estructurada para cortar lazos.
0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda — cláusulas de guarda y retornos anticipados.
Antipatrón: Uso de salto goto hacia atrás vulnerando programación estructurada¶
Síntoma en el código del estudiante¶
Un goto salta hacia atrás a una etiqueta anterior para repetir un bloque,
simulando un lazo:
repetir:
/* ... */
goto repetir;Diagnóstico¶
Mecanismo del defecto¶
goto transfiere el control a la etiqueta sin pasar por ninguna estructura
(ISO/IEC 9899:2011 §6.8.6.1). Un salto hacia atrás reconstruye a mano un lazo:
la condición de corte queda dispersa en el cuerpo y la cantidad de repeticiones
no se lee en ningún encabezado. El flujo deja de ser un árbol y se vuelve un
grafo.
Consecuencia observable¶
El código funciona, pero cada lector debe rastrear los saltos para entender cuántas veces se repite el bloque y bajo qué condiciones. Un cambio en el cuerpo puede volver el salto infinito o inalcanzable, y el compilador no lo ayuda. Es el llamado “código espagueti” que la programación estructurada busca evitar.
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.8.6.1 define goto y admite cualquier dirección. El
teorema de Böhm–Jacopini garantiza que todo programa con goto puede
reescribirse con secuencia, selección e iteración. La cátedra prohíbe el uso
general (regla 0x1006h) y tolera solo el salto hacia adelante a un bloque de
limpieza (regla 0x1011h).
Corrección idiomática¶
❌ Código con el antipatrón¶
int i = 0;
repetir:
if (i >= n)
{
goto fin;
}
procesar(valores[i]);
i++;
goto repetir;
fin:
return 0;✅ Código refactorizado¶
for (int i = 0; i < n; i++)
{
procesar(valores[i]);
}
return 0;El for reúne inicialización, cota e incremento; no hay etiquetas ni saltos que
rastrear y agregar un corte equivale a modificar la condición.
Errores típicos al compilar o ejecutar¶
No hay error de compilación. Con -Wall, GCC y Clang pueden no advertir nada.
El riesgo es de mantenimiento: si se olvida el incremento o el goto
condicional, el lazo se vuelve infinito. Un cambio en el cuerpo puede
dejar la etiqueta fin inalcanzable.Checklist de verificación¶
¿Hay algún
gotoque salte hacia atrás?¿El salto simula un lazo que podría ser
forowhile?¿La condición de corte está dispersa en el cuerpo?
¿Puedo reescribir el bloque con una estructura de repetición canónica?
Reglas relacionadas¶
0x1006h: No utilizar la instrucción goto — norma este antipatrón: prohibición general del
goto.0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos — única excepción tolerada: limpieza hacia adelante.
0x1003h: Utilizá el lazo for para iteraciones con rango o contador definido y while para lazos controlados por condiciones lógicas — elegir el lazo canónico correcto.