Regla 0x010Fh: Prohibición de constantes numéricas mágicas en índices de arreglos
Nomenclatura e identificadores (0x01XX)
0x010Fh: Prohibición de constantes numéricas mágicas en índices de arreglos¶
Enunciado normativo¶
NO DEBE accederse a posiciones fijas de un arreglo con literales mayores que 2 (
vec[7]). Esos índices DEBEN expresarse con constantes simbólicas (#defineoenum) que nombren su significado de dominio. Los índices0,1y2, y las variables de iteración, quedan exceptuados por su uso idiomático.
¿Por qué existe esta regla?¶
El problema¶
Un literal como registro[7] no dice qué hay en la posición 7 ni por qué se la
elige. Toda la semántica del programa —que la columna 7 es el total, que el
campo 3 es el legajo— queda grabada en un número que el lector debe descifrar.
Peor: si la estructura cambia de tamaño o de orden, los índices literales quedan
desalineados sin que nada avise, y un acceso fuera de límites es comportamiento
indefinido. Un nombre simbólico convierte el número en documentación y en un
único punto de cambio.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | Reordenar los campos invalida todos los índices literales sin error de compilación. |
| Comportamiento indefinido | Si el literal excede la dimensión —por ejemplo tras reducir el arreglo—, el acceso es fuera de límites. |
| Legibilidad | El lector debe inferir el significado de cada posición. |
| Mantenibilidad | Cambiar una posición obliga a buscar el literal en todo el archivo. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.5.2.1 define la indexación de arreglos y §6.4.4 los
literales enteros; el estándar no prohíbe los números, pero el acceso fuera de
límites es comportamiento indefinido. La cátedra exige símbolos con significado
de dominio porque el índice es, en la mayoría de los ejercicios, un campo de un
registro o una columna de una matriz. Se articula con 0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes, que
recomienda enum para conjuntos de estados, y con 0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos, que exige
validar los límites.
Alcance y excepciones¶
Aplica a accesos con índice literal mayor que 2. No aplica a los índices
0, 1 y 2, reservados para operaciones como intercambiar dos elementos o
leer el primero, ni a variables de iteración (v[i]), que no son mágicas. No
alcanza a las dimensiones de declaración (int m[3][3]), que describen el tipo
y no un acceso, aunque a partir de 3 conviene igualmente una constante.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Índice literal sin significado¶
registro[7] = 100;Por qué falla: no se sabe qué es la posición 7. Si el arreglo tiene menos de ocho elementos, además es un acceso fuera de límites. El número no documenta el campo ni se actualiza si la estructura cambia.
❌ Contraejemplo 2 — Índices literales en una comparación¶
if (fila[3] > fila[2]) {
intercambiar(&fila[3], &fila[2]);
}Por qué falla: 3 y 2 aquí representan campos distintos, pero nada lo dice; el
lector no puede distinguir un campo de un desplazamiento casual. fila[2] queda
exceptuado por la regla, pero mezclar 2 y 3 en la misma expresión vuelve
necesario nombrar ambos.
✅ Ejemplo conforme 1 — Constante simbólica con significado¶
#define INDICE_TOTAL 7
int registro[8];
registro[INDICE_TOTAL] = 100;Por qué cumple: INDICE_TOTAL declara qué mide esa posición y el arreglo tiene
espacio suficiente; el valor está dentro de los límites. El nombre es el único
lugar donde cambiar el desplazamiento.
✅ Ejemplo conforme 2 — Enumeración de campos e iteración¶
enum {
COL_NOMBRE = 0,
COL_EDAD = 1,
COL_LEGAJO = 2
};
int fila[3];
fila[COL_LEGAJO] = 12345;
for (size_t i = 0; i < 3; i++) {
printf("%d\n", fila[i]);
}Por qué cumple: cada campo tiene nombre (enum conforme a 0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes), el
acceso es legible y la iteración usa una variable, no un literal. fila[0] y
fila[1] podrían exceptuarse, pero nombrarlos hace el código más claro.
⚠️ Casos límite¶
Índices
0,1,2: permitidos por la regla; se recomienda nombrarlos cuando su significado de dominio es relevante.Desplazamientos:
v[i + 1]usa un literal pequeño como offset; no es un índice fijo mágico.Matrices:
m[0][0]sigue exceptuado;m[3][4]conviene nombrarlo.Dimensiones:
int m[3][3]describe el tipo; a partir de 3 se prefiere una constante.Cadenas:
s[0]es el primer carácter; no requiere símbolo.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Reporta accesos arreglo[N] con N > 2 literal. |
gcc / clang | gcc -Wall -Wextra -std=c11 -c archivo.c | No reporta el número mágico, pero sí un acceso fuera de límites detectable. |
| Revisión manual | — | Buscar corchetes con literales mayores que 2. |
Checklist de autocontrol¶
Ningún acceso fijo a arreglo usa un literal mayor que 2.
Di significado a cada posición con
#defineoenum.El índice simbólico está dentro de los límites (0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos).
Los lazos usan variables de iteración, no posiciones fijas.
Reglas relacionadas¶
0x300Dh: Utilizá enum en lugar de ‘números mágicos’ para conjuntos de estados y valores constantes —
enumen lugar de números mágicos para conjuntos de estados.0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos — validar los límites del arreglo antes de acceder.
0x5001h: Los arreglos estáticos deben ser creados con un tamaño fijo en tiempo de compilación — arreglos con tamaño fijo en tiempo de compilación.
0x010Eh: Prescindí de identificadores genéricos con sufijo numérico o afijos (numero1, num_1, n_a, a_n) — evitar familias de variables numeradas.