Regla 0x301Ch: Detector de variables locales no inicializadas con modificador const
Memoria, punteros y tipos (0x30XX)
0x301Ch: Detector de variables locales no inicializadas con modificador const¶
Enunciado normativo¶
Toda variable declarada con el calificador
constDEBE inicializarse en la misma sentencia de su declaración. NO DEBE declararse un objetoconstsin valor.
¿Por qué existe esta regla?¶
El problema¶
const significa que el objeto no puede modificarse después de su creación. En
C no hay constructores ni una lista de inicialización diferida: la única
oportunidad de darle un valor a un objeto const es su declarador. Si se
declara const int limite; sin inicializador, no queda ningún camino legal para
asignarle un valor: limite = 10; es un error de compilación porque el objeto
es de sólo lectura. El resultado es un objeto inmutable al que nunca se le dio
contenido; leerlo produce un valor indeterminado, y el estándar trata esa
lectura como comportamiento indefinido para objetos automáticos.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Compilación | limite = 10; produce error: assignment of read-only variable 'limite'. |
| Comportamiento indefinido | Leer el objeto const sin inicializar es leer un valor indeterminado. |
| Bug silencioso | gcc advierte sólo cuando detecta el uso; si no, el valor basura viaja hasta el resultado. |
| Mantenibilidad | El lector no puede saber cuál debía ser el valor original. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.7.9 (Initialization), §6.7.3 (Type qualifiers) y §6.2.4
(Storage durations) sustentan la regla: un objeto automático sin inicializador
explícito tiene valor indeterminado (§6.7.9p10), y un objeto const no admite
asignación posterior. La cátedra la exige porque un const vacío suele esconder
la intención de “declarar y luego calcular”; ese patrón se escribe con una
variable no const y, si se desea, una copia const al final del cálculo.
Alcance y excepciones¶
Aplica a objetos locales y a los de duración estática de nivel de archivo. Los
de duración estática se inicializan a cero por el estándar (§6.7.9p10), pero la
cátedra pide el inicializador explícito por claridad. No aplica a parámetros
const (el inicializador es el argumento) ni a una declaración extern const
(es sólo una declaración, no una definición). En un miembro const de struct,
el valor se aporta en el inicializador del agregado.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — const usado como tamaño de arreglo¶
const int limite;
int valores[limite];Por qué falla: limite nunca recibe valor y se usa como dimensión. Además, el
arreglo resulta un VLA, prohibido por 0x5001h: Los arreglos estáticos deben ser creados con un tamaño fijo en tiempo de compilación; los dos defectos se
potencian.
❌ Contraejemplo 2 — const leído en una fórmula¶
const double iva;
double total = base * (1.0 + iva);Por qué falla: compila con advertencia, pero iva contiene basura de la pila.
El resultado es indefinido y no reproducible entre ejecuciones.
✅ Ejemplo conforme 1 — Escalar inicializado¶
const int limite = 100;
int valores[100];Por qué cumple: el valor queda fijado en la declaración y el arreglo tiene tamaño constante en tiempo de compilación.
✅ Ejemplo conforme 2 — Varios niveles de const¶
const double iva = 0.21;
const char * const mensaje = "ok";Por qué cumple: en la segunda línea, tanto el puntero como el contenido apuntado son inmutables y ambos quedan fijados al declarar; el orden de calificadores sigue 0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’.
⚠️ Casos límite¶
static const int x;de archivo: el estándar lo inicializa a cero, pero se escribe= 0para no depender de esa regla.int * const p = &v;(puntero constante): debe inicializarse; en cambioconst int *p;(puntero aconst) sí puede declararse vacío porque el puntero es mutable.Arreglo
const:const int v[3] = {0};inicializa el agregado, ver 0x3018h: Inicialización idiomática de agregados con {0} en lugar de memset inmediato.Prototipos:
void f(const int x)no requiere inicializador; el parámetro se inicializa con el argumento.No confundir con 0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’: ésa ordena los calificadores, ésta exige el valor.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Reporta un const local declarado sin inicializador. |
gcc / clang | gcc -Wall -Wextra -std=c11 -c archivo.c | warning: uninitialized const 'limite' cuando el uso es visible. |
| Revisión manual | — | Declaraciones const tipo nombre; sin = valor. |
Checklist de autocontrol¶
Todo
constque declaré tiene su= valoren la misma línea.Distingo un puntero constante (
int * const) de un puntero aconst(const int *).No usé un
constvacío como tamaño de arreglo.Los agregados
constusan su inicializador de llaves.
Reglas relacionadas¶
0x7001h: Siempre debés inicializar las variables a un valor conocido — inicializar toda variable a un valor conocido.
0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’ — orden canónico
const tipo.0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique —
consten parámetros puntero de sólo lectura.0x3018h: Inicialización idiomática de agregados con {0} en lugar de memset inmediato — inicialización de agregados con
{0}.0x5001h: Los arreglos estáticos deben ser creados con un tamaño fijo en tiempo de compilación — prohibición de arreglos de longitud variable.