Regla 0x3010h: Las variables que representan tamaños o índices de arreglos deben ser de tipo size_t
Memoria, punteros y tipos (0x30XX)
0x3010h: Las variables que representan tamaños o índices de arreglos deben ser de tipo size_t¶
Enunciado normativo¶
Toda variable que represente una cantidad de bytes, una cantidad de elementos o un índice de arreglo DEBE declararse como
size_t, y NO DEBE declararse comoint. La variable de iteración del recorrido también DEBE sersize_tcuando se compara contra una cantidad.
¿Por qué existe esta regla?¶
El problema¶
size_t es el tipo entero sin signo que el estándar usa para representar
tamaños: es el tipo del resultado de sizeof y de strlen, y el que esperan
malloc, memcpy y las funciones de arreglos. Es lo suficientemente ancho para
contener el tamaño máximo de cualquier objeto en memoria.
Usar int para un tamaño introduce dos problemas: puede no ser lo bastante
grande (un arreglo grande desborda) y tiene signo. Al comparar un int con un
size_t, el int se convierte a sin signo; un valor negativo se transforma en
un número enorme y la comparación i < cantidad se vuelve siempre verdadera.
Ese es el origen de los desbordamientos por índice negativo.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug lógico | Un índice -1 convertido a size_t es mayor que cualquier cantidad. |
| Desbordamiento | Un int no puede indexar arreglos de más de INT_MAX elementos. |
| Portabilidad | int y size_t cambian de ancho entre plataformas. |
| Mantenibilidad | Conversiones de signo dispersas y advertencias de compilador. |
Fundamento en el estándar y en la cátedra¶
C11 §7.19 define size_t en <stddef.h> como el tipo sin signo del resultado de
sizeof. La cátedra lo exige para toda magnitud de memoria, y lo combina con
0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos, que prohíbe acceder a un arreglo sin validar el índice. Juntas
garantizan comparaciones correctas y sin conversiones de signo.
Alcance y excepciones¶
Aplica a tamaños, índices, cantidades de elementos, resultados de strlen y
sizeof, y variables de iteración de arreglos. No aplica a cantidades que
pueden ser negativas por contrato, como diferencias o centinelas; para ellas
elegí un tipo con signo explícito y documentá el rango. La impresión de size_t
usa el especificador %zu.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Longitud guardada en int¶
int longitud = strlen(cadena);
for (int i = 0; i < longitud; i++)
{
procesar(cadena[i]);
}Por qué falla: strlen devuelve size_t y la asignación lo convierte a int,
lo que puede truncar una cadena muy larga. Si longitud fuera negativa por
cualquier error de cálculo, el lazo no iteraría nunca. El tipo correcto es
size_t.
❌ Contrajemplo 2 — Comparación de int negativo contra size_t¶
int indice = obtener_indice();
size_t cantidad = contar_elementos();
if (indice < cantidad)
{
acceder(indice);
}Por qué falla: si obtener_indice devuelve -1, la conversión a size_t lo
transforma en SIZE_MAX y la condición -1 < cantidad es falsa o verdadera
según la conversión, pero nunca detecta el error. Hay que validar
indice >= 0 antes de comparar contra un tipo sin signo.
✅ Ejemplo conforme 1 — size_t de punta a punta¶
size_t longitud = strlen(cadena);
for (size_t i = 0; i < longitud; i++)
{
procesar(cadena[i]);
}El tipo de la longitud coincide con el de strlen y el índice con el de la
comparación. No hay conversiones implícitas de signo y el lazo es correcto para
cualquier tamaño que size_t pueda representar.
✅ Ejemplo conforme 2 — Índice con signo validado antes de convertir¶
int posicion = buscar_posicion(clave);
if (posicion >= 0 && (size_t)posicion < cantidad)
{
acceder((size_t)posicion);
}Cuando el valor proviene de una función que puede devolver -1, se valida el
signo antes de la conversión a size_t. Recién entonces la comparación es
segura. Este patrón se complementa con 0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos.
⚠️ Casos límite¶
printf: usá%zuparasize_t; con%del comportamiento es indefinido porque el tipo no coincide.Diferencias: restar dos
size_tpuede “dar la vuelta” si el resultado es negativo; usá un tipo con signo si la diferencia puede serlo.ssize_t: en POSIX representa cantidades que pueden ser negativas; no es portable fuera de ese entorno, pero es preferible aintcuando existe.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Variables de tamaño o índice declaradas como int. |
gcc / clang | gcc -Wall -Wextra -Wsign-compare -Wsign-conversion -std=c11 ... | comparison of integer expressions of different signedness. |
cppcheck | cppcheck --enable=all archivo.c | Sign conversion o truncation de size_t a int. |
Checklist de autocontrol¶
¿Las longitudes y cantidades son
size_t?¿Las variables de iteración de arreglos son
size_t?¿Validé el signo antes de convertir un
intasize_t?¿Uso
%zupara imprimirsize_t?¿Evité mezclar
intysize_ten comparaciones?
Reglas relacionadas¶
0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos — la validación de límites se apoya en el tipo correcto.
0x300Bh: Usá siempre sizeof en las asignaciones de memoria dinámica, prefiriendo sizeof(*ptr) —
sizeofya devuelvesize_t; no lo trunques.0x5004h: Todas las operaciones con cadenas deben ser seguras — las operaciones seguras con cadenas usan estos tamaños.
0x100Dh: Prohibición de condiciones de parada compuestas complejas en lazos for — la condición simple del lazo se apoya en cotas del tipo correcto.